# SeaTable Admin Manual
Admin documentation for SeaTable — installation, configuration, authentication, upgrade, maintenance, and cluster deployment guide.
Base URL: https://admin.seatable.com
## Introduction
Source: https://admin.seatable.com/
# Welcome to the SeaTable Admin Manual
## Who is this Manual for?
You want to run your own **SeaTable Server**, then this SeaTable Admin Manual (Manual) is the place to be!
SeaTable is a sophisticated software solution comprised of multiple components that must seamlessly interact. Therefore, we advise running your own server only if you possess a solid understanding of topics such as **Docker**, **Docker Compose**, **network ports**, **proxies**, and Linux **bash commands**. Even the best documentation can not describe everything.
If you want to use SeaTable, but you don't want to run your own server, SeaTable GmbH offers two other products next to **SeaTable Server**:
??? abstract "SeaTable Cloud: public SAAS"
SeaTable Cloud is the product of choice for small- and medium-sized enterprises that just want to use SeaTable - quickly and at transparent cost. SeaTable Cloud can be used free-of-charge with the Free subscription. Registration for SeaTable Cloud requires only an email address. More features and higher resource limits are available in SeaTable Cloud's [paid subscriptions](https://seatable.com/en/preise/).
[Register now for SeaTable Cloud](https://seatable.com/registration/){ .md-button .md-button--primary }
??? tip "SeaTable Dedicated: private SAAS"
[SeaTable Dedicated](https://seatable.com/dedicated/) is a custom SeaTable Server instance for you and your team operated by the SeaTable experts. You define which URL to use, which logo or color code should greet your users.
**Important**: SeaTable Dedicated requires a minimum of 100 Users.
[Contact us and get a quote](https://seatable.com/contact/){ .md-button .md-button--primary }
## Scope of this Manual
This Manual covers all relevant admin topics, from installation, configuration, upgrade, and maintenance, and provides background information on software architecture, requirements, and development.
This Manual is NO **user** manual. For information about how to use SeaTable, please refer to the [user documentation](https://seatable.com/help/).
If you are a **developer** looking for development resources, please check out the [Developer Manual](https://developer.seatable.com) and the [API Reference](https://api.seatable.com).
This is not the place for discussion either. You can ask questions about SeaTable in the [SeaTable Forum](https://forum.seatable.com). Looking forward to seeing you there!
## Contributing to this Manual
You found an error in the Manual or you see the need to elaborate on a topic, please create a pull request. We appreciate your contribution!
## What is SeaTable?
SeaTable is a no-code database and app-building platform. At the first glimpse it looks like an online spreadsheet solution like Google Sheets, but under the hood it offers so much more. SeaTable helps you to record and manage all kinds of scattered information. Use Filters, Sortings or Group to work collaboratively with friends and colleagues. Visualize any data with various plugins like Kanban, Gallery or Calendar.
With APIs and SDKs, you can quickly scale to your needs, automate data processing and automate business processes.
Main features include:
- A spreadsheet like interface to record data supporting collaborative editing.
- A form app to collect data from outside.
- Mobile ready UI to be used on browsers in mobile system to view and collect data.
- Comprehensive API and SDK for adding extensions.
- Filters, sorts, charts and pivotal tables to visualize and analyze data.
This Manual will help you to install, configure and update your own SeaTable Server.
## Installation
This Manual provides two different approaches to installing SeaTable Server.
### Single-Node Installation
There is a _Single-Node Setup_, where all components of SeaTable Server are installed on one server or virtual machine. All services can be reached by a single URL. The installation is straightforward thanks to the consequent usage of Docker. This setup is easy for testing and production for up to 100 users.
[Let's begin with the Single-Node installation](installation/basic-setup.md){ .md-button .md-button--primary }
### Advanced Setup
The _Advanced Setup_ section doesn't entail a distinct installation method; rather, it offers detailed guidance on operating each component independently. It equips you with the knowledge needed to scale your SeaTable Server effectively. Whether you're seeking insights to enhance performance or aiming to construct a highly available cluster setup capable of supporting hundreds of thousands of users, this section provides comprehensive instructions to meet your objectives.
## Impressions of SeaTable
### Login Page
Every user accessing SeaTable via the browser must undergo authentication, typically through a combination of email and password. However, SeaTable goes beyond traditional methods, offering support for advanced authentication protocols such as LDAP, OAuth, and SAML. This ensures flexibility and security in user authentication, catering to diverse organizational needs and preferences.

### Home Page
At SeaTable's Home Page, you gain seamless access to all your bases, each of which functions as a distinct database or process. These bases serve as the foundation for organizing and managing your data, offering versatility in structuring your information according to your specific needs. Whether you're storing project data, tracking tasks, or managing customer information, SeaTable's intuitive interface empowers you to streamline your workflows and harness the full potential of your data assets.

### Base Editor
The base editor serves as the central hub of SeaTable, facilitating the structured storage of diverse information types for you and your team. With collaborative features seamlessly integrated, you can collectively work on your data in real-time. Utilizing the columns within your base, you can effortlessly create customizable input forms and unique views, empowering you to share specific data subsets with others efficiently.
You have complete freedom in designing your bases. You determine the data to be saved and the manner in which you interact with it. Whether it's organizing project details, tracking inventory, or managing contacts, SeaTable empowers you to tailor your bases to your specific needs and workflows.

---
Source: https://admin.seatable.com/introduction/architecture/
# Architecture
## Overview
SeaTable Server uses Docker/Docker Compose for easy deployment and upgrades.
A SeaTable Server instance consists of a handful of Docker containers. The following diagram is a simplified representation of the required Docker containers deployed in the [single node setup](../installation/basic-setup.md).
```mermaid
flowchart TB
Client@{ shape: pill, label: "Client"}
Client<-->A
subgraph s[SeaTable Server instance]
subgraph d[Docker Containers]
A[caddy 80, 443]
B[seatable-server 80]
C[mariadb 3306]
D[redis 6379]
A<-->B
B<-->C
B<-->D
end
F@{ shape: bow-rect, label: "Storage"}
end
```
The numbers designate the ports used by the containers. Port 443 in the container `caddy` must be exposed. Port 80 must also be exposed when a Let's Encrypt SSL certificate is to be used. All other ports are internal ports that are only available within the Docker network.
All Docker containers read from and write to local disk. The containers `caddy`, `seatable-server`, and `mariadb` employ Docker volumes.
In an extended setup, additional, optional Docker container can be deployed to add functionality to SeaTable Server. The diagram below describes all Docker containers and their interactions required for a SeaTable Server instance integrated with office editor, Python pipeline, virus scan, and whiteboard.
```mermaid
flowchart TB
Client@{ shape: pill, label: "Client"}
Client<-->C
subgraph s[SeaTable Server instance]
direction LR
subgraph d[Docker Containers]
direction TB
C[caddy 80,443]
SS[seatable-server 80]
MDB[mariadb 3306]
R[redis 6379]
OO[collabora/onlyoffice 6232/6233]
Tld[tldraw 6239]
CAV[clamav 3310]
PSc[python-scheduler]
PSt[python-starter]
PR[python-runner]
C<-->SS
C<-->Tld
C<-->OO
SS<-->MDB
MDB<-->PSc
subgraph p[Python Pipeline]
direction TB
PSc<-->PSt
PSt<-->PR
end
SS<-->R
SS<-->OO
SS<-->Tld
SS<-->CAV
SS<-->PSc
end
F@{ shape: bow-rect, label: "Storage"}
end
```
By default, SeaTable requires only a single publicly accessible URL. However, some user-facing services (such as Collabora, OnlyOffice, and tldraw) are exposed on separate ports (typically between 6230 and 6239). Experienced administrators can configure separate URLs or subdomains for these services if needed, for example by creating custom YAML files.
Note: Not all services support operation under subfolders. For example, tldraw cannot be accessed via a subfolder.
The rest of this article focuses exclusively on the required containers and services of a SeaTable Server instance.
## Container caddy
Caddy is a flexible web proxy. Its job is to offer a central gateway for the SeaTable Server instance.
Caddy is easy to configure and excels at facilitating SSL configuration and management, either with Let's Encrypt or custom certificates.
## Container seatable-server
The container `seatable-server` is home to several services. The nginx service is the gateway in the container.
```mermaid
flowchart LR
subgraph s[SeaTable Server Container]
A[nginx 80]
B[dtable-web 8000]
C[dtable-server 5000]
D[dtable-db 7777]
E[api-gateway 7780]
F[dtable-storage-server 6666]
G[dtable-events]
H[seaf-server 8082]
A<-- / -->B
A<-- /api-gateway -->E
A<-- /seafhttp -->H
B<-->C
B<-->D
B<-->F
E<-->C
E<-->D
C<-->F
C<-->G
D<-->F
D<-->G
end
```
All services in the container `seatable-server` connect to the containers `mariadb` and `redis` to read (and write). All components also read (and write) to local disk.
Originally (a long time ago), SeaTable was going to be called `dtable` (short for _database table_). Although this term was later replaced with *SeaTable*, many internal components and log entries still use the old name `dtable`. Whenever you see `dtable`, it simply refers to a component of SeaTable.
### dtable-web
The task of the service dtable-web is to deliver all pages except for the bases themselves. This includes essential features such as the login page, home page, system administration area, team administration, personal settings, and API endpoints. All these functionalities are provided by dtable-web, which is built on the Django framework.
### dtable-server
When accessing a base, you'll be directed to the base editor, which is provided by the dtable-server service. This editor loads the base's content from a JSON file, presenting it in a familiar spreadsheet interface and enabling real-time collaborative work on all data within the base. Each modification is promptly saved to the operation log (stored in MariaDB), and within minutes, these changes are persisted as a JSON file and transmitted to dtable-storage-server for storage in the attached storage system.
### dtable-db
dtable-db extends the functionality of dtable-server, offering an SQL-like query language to interact with base data. Additionally, it serves as the interface for accessing the Big Data Backend.
### seaf-server
When utilizing a file or image column in your base, the actual files are stored separately from the JSON object, with the JSON object containing only links to these files. The seaf-server service manages the storage and retrieval of these files, ensuring they can be accessed within the base. Seafile currently supports local storage or S3 storage, and seaf-server is responsible for appropriately storing the files based on the chosen storage method.
### dtable-storage-server
The dtable-storage-server is a simple abstract layer upon the chosen storage. SeaTable Server supports file system and S3-compatible object storage.
### dtable-events
When actions are not executed immediately but with a time delay, SeaTable employs the dtable-events service, essentially the interface to the Redis cache. dtable-events effectively manages various tasks and their status, ensuring efficient task execution within the system.
### api-gateway
The api-gateway is a proxy for dtable-server and dtable-db. All API calls for [base operations](https://api.seatable.com/reference/getbaseinfo) are routed through this component. It is also essential for the effective enforcement of API rate and request limits.
## Container mariadb
SeaTable uses MariaDB to store user, group and team information as well as metadata for bases. Additionally, MariaDB stores the operation log. The operation log (saved in the database table `dtable_db.operation_log`) is the base journal. It records all modifications made within all bases of the SeaTable Server instance. (While SeaTable stores all base modifications in MariaDB, it doesn't store the actual base content. Instead, bases are managed within dtable-server and regularly persisted to dtable-storage-server for long-term storage.)
SeaTable Server uses four database tables:
- **ccnet_db**: information about users, groups and teams (or organizations)
- **seafile_db**: metadata information of the file storage
- **dtable_db**: application level data, including base metadata, operation log, sessions, automation rules
- **scheduler**: log information for SeaTable Server's Python Pipeline
## Container redis
Redis, an in-memory data store, performs several tasks for a SeaTable Server instance:
- Caching for Django, which is used for SeaTable's web interface and all API endpoints
- Cache application level data obtained from databases (e.g. session cache, user information cache, group and organization list cache)
- Sending messages from dtable-web/dtable-server to dtable-events - it serves as an event queue to save internal tasks and statuses
In versions up to SeaTable Server 5.1, Memcached, an in-memory key-value store, was used to cache the Django framework.
## Storage
By default, SeaTable Server stores user data in the following structure on the local disk:
```bash
/opt/seatable-server/seatable
├── conf
├── db-data
├── logs
├── pids
├── scripts
├── seafile-data
├── seahub-data
└── storage-data
```
These directories contain the following content:
- **conf**: configuration files for SeaTable Server components (see [Configuration](../configuration/overview.md))
- **logs**: log files generated by SeaTable Server components (see [Logging](../maintenance/logs.md))
- **db-data**: data stored in big data storage
- **seahub-data**: avatars and image thumbnails
- **storage-data**: base data, base snapshots, and backup of big data
- **seafile-data**: assets (files and images) saved in bases
`/opt/seatable-server/` is mounted as a Docker volume in the Docker container `seatable-server` when SeaTable Server is started.
SeaTable can, depending on the [configuration](../installation/advanced/s3.md), store the following items in S3 buckets instead of in the file system:
- storage-data
- seafile-data
- avatars in seahub-data
(The content of the data in db-data cannot be stored in S3 due to its idiosyncratic format.)
## SeaTable Backends
SeaTable employs two distinct backends: the **default backend**, which supports all features including real-time collaboration in the base editor, and the **big data backend**.
The latter was developed to address a technical size limitation, which by default restricts the maximum number of rows within a base to 100k. The Big Data backend enables the storage of millions of rows in a single base, overcoming this limitation. However, due to the vast amount of data handled, not all functions are supported by the big data backend. Particularly, real-time collaboration is not supported for data stored in the big data backend.
### Default Backend (JSON-file based backend)
The core of a SeaTable Server lies in its base editor, facilitating real-time collaborative work directly within the browser.
When a base is opened in the base editor, dtable-server initiates a request to the dtable-storage-server to retrieve the corresponding JSON-file from storage. Subsequently, dtable-server renders the base and loads its content into the server's memory. All modifications are stored in memory and simultaneously recorded in the operation log within the MariaDB database. Every five minutes, dtable-server automatically saves these changes to the file system, persisting them in the JSON-file.
Furthermore, the dtable-storage-server generates a snapshot of the base every 24 hours, capturing any changes that have occurred in the interim. Essentially, a snapshot is a complete copy of the JSON-file.

Initially, it may seem counterintuitive that SeaTable saves base data in a JSON-file rather than directly in the MariaDB database. However, this decision stems from the efficiency of SQL tables in handling vast numbers of rows. The challenge arises when altering the database structure, such as adding new columns, renaming columns, or changing column types in a table containing hundreds of thousands of rows. In such cases, direct database storage proves inefficient.
To address this issue, SeaTable opts to persist base data in JSON-files instead. While this JSON-based backend approach offers flexibility, it also imposes a limitation on base size. A technical constraint of 200MB per JSON-object translates to a default maximum of 100k rows per base. When nearing this limit, records can be transferred to the Big Data storage via the archive view operation, mitigating potential issues.
### Big Data Backend (SQL-like database)
The second backend, known as the _big data backend_, diverges from the conventional JSON-file storage method by utilizing an SQL-like database capable of accommodating millions of rows within a base. [Activating the Big Data backend](https://seatable.com/help/enable-big-data-storage-seatable) for a base prompts SeaTable to create a new database structure tailored to accommodate large datasets.
To access data stored in the big data backend, users must create a [Big Data View](https://seatable.com/help/create-big-data-view-seatable), which, unlike conventional views, loads a preview of up to 1k rows by default. To retrieve additional rows, users can make requests within the web interface to get more data.
Unlike the default backend, the Big Data backend does not load data into the server's memory, rendering real-time collaboration unsupported. Given the challenges of interacting with millions of rows within a browser-based spreadsheet interface, users typically access such large datasets via the **SQL query Plugin**, the [SeaTable API](https://api.seatable.com) or through the SQL-like query language provided by dtable-db.
---
Source: https://admin.seatable.com/introduction/security/
# Security measures
Security is more than just activating a function or implementing a web-application firewall. Security is an ongoing process with a holistic view on all relevant topics. We try to define sensible default values implementing best practices to improve the security without creating too many restrictions that might produce problems with some older clients.
## Web-Security
Due to the fact that SeaTable is a mainly used via the browser, we took quite some effort to implement good security measures. HTTPS is mandatory by default, modern ciphers are required and we enforce some security headers to prevent against typical script kiddies attacks.
This configuration approach delivers good results, that are confirmed by known security experts in the internet:
- A+ from [https://www.ssllabs.com/](https://www.ssllabs.com/ssltest/analyze.html?d=cloud.seatable.io)
- A from [https://securityheaders.com/](https://securityheaders.com/?q=https%3A%2F%2Fcloud.seatable.io)
- 100% from [internet.nl](https://internet.nl/site/cloud.seatable.io/)
- 80/100 or B+ from [https://observatory.mozilla.org/](https://developer.mozilla.org/en-US/observatory/analyze?host=cloud.seatable.io)
## Network security
SeaTable's architecture encompasses a constellation of services and containers, each fortified with robust security measures. Our approach emphasizes the publication of only a singular service to the internet, strategically limiting the attack surface.
Complementing this, network segmentation is rigorously enforced, ensuring containers are cordoned off from one another and allowing only vital communication within the ecosystem. In meticulous detail, we've established distinct networks: one tailored for containers necessitating public accessibility and another reserved for internal, non-public traffic.
This meticulous design ensures a fortified defense posture, shielding SeaTable's infrastructure from potential threats while safeguarding the integrity of its operations.
## Security scans and vulnerabilities
Ensuring security in CI deployment is paramount for us. This entails maintaining strict control over our deployment pipeline, implementing rigorous linting and code formatting checks, and conducting automatic testing with CVE vulnerability scanners. These measures collectively contribute to the generation of up-to-date container images, safeguarding our infrastructure against potential vulnerabilities.
## Documentation, Support and source code
While it's true that any software product can simply be run, that approach doesn't align with our philosophy. Our mission is to create the world's leading self-hosted no-code database and app building platform. In pursuit of this goal, we prioritize several key components:
- Comprehensive documentation to empower users at every step.
- A responsive and knowledgeable support team to swiftly address any inquiries or issues.
- Availability of the source code, with exceptions made only to protect our intellectual property.
By adhering to these principles, we aim to provide a seamless and empowering experience for our users, fostering innovation and creativity in their projects.
---
Source: https://admin.seatable.com/introduction/requirements/
# Requirements
One of the main advantages of SeaTable against other solutions is, that you can run SeaTable on your own hardware or on any server you like. Still there are some requirements:
- Linux-Server with Root-Shell
- Public domain pointing to your server
- Open Ports for HTTP and HTTPS access (probably more ports for other components)
- The ports should not be already in use by another proxy such as NGINX or Apache
Does this sound complicated? Not really. So let's get started.
[Let's begin with the installation in the root-shell](../installation/basic-setup.md){ .md-button .md-button--primary }
If you need more information, you can get more details in this article.
## Platform support
SeaTable uses `docker` and `docker compose`. Therefore it should run as long as docker virtualisation is available. Still we recommend **Debian 11 or newer** because we always use Debian for production and testing.
Currently only x86/x64 architecture is officially supported. Bigger customers might get support with ARM based systems.
## Hardware
SeaTable Server requires at least
- 4 CPU cores
- 8 GB RAM
- 50 GB SSD
These resources guarantee good performance for most applications with up to 100 users. When bases become large or the number of users increase, **more RAM** is needed since SeaTable stores the bases in memory. More CPU could help, but has much lower impact on system performance.
As soon as you have more than 100 users, you should consider extending your SeaTable Platform and move some components to separate VMs.
These hardware requirements are for SeaTable Server. If you install additional components like n8n, collabora online or onlyoffice the requirements for these resources stack up and you have to add additional resources.
For sure we need a **root shell** on this server to execute the installation commands.
## Public available domain
This manual assumes that you have **one domain or subdomain** that points to your public IP address of your server.
```mermaid
flowchart LR
A["User / Browser"]
B[Domain / Subdomain Ports 80+443]
C[Server or VM with Docker]
A-->B
B-->C
```
For sure, it is possible to run SeaTable without an internet connection (air-gapped) or with custom SSL certificates. This requires additional settings which are explained in separate chapters.
## Ports
SeaTable needs by default only the default ports **80 (HTTP)** and **443 (HTTPS)**.
Most of the additional components will require **additional ports** in the range of **6230 to 6240**. You have to open the firewall or create port forwardings if you want to use these functions. If you don't use this component, the port can stay closed.
### List of required ports
- **80**: HTTP access is necessary to receive a Let's Encrypt certificate
- **443**: HTTPS is the main entrance to SeaTable Server
### List of optional ports
- **6230**: Uptime Kuma
- **6231**: n8n
- **6232**: Collabora Online
- **6233**: OnlyOffice
- **6235**: Zabbix
## License
**SeaTable Enterprise Edition** requires a license to start. A free license for two years and three users can be obtained via the command line, which will be explained during the installation. Licenses with more than three users can be obtained from [SeaTable Website](https://seatable.com/prices/).
**SeaTable Developer Edition** does not require a license.
---
Source: https://admin.seatable.com/introduction/system-limitations/
# System limitations
The following limitations apply to SeaTable Server as well as SeaTable Cloud and SeaTable Dedicated, unless explicitly stated otherwise here or on the relevant product page.
For API-related limits, please see the SeaTable [API reference](https://api.seatable.com/reference/limits).
| Category | Limitation Type | Limit | Additional Notes |
| :----------------------- | :-------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bases | Rows | 100 000 | The base becomes read-only when exceeding this limit. The limit can be modified in `dtable_server_config.json`/through the `BASE_WRITABLE_LIMIT` environment variable. |
| | Rows 2 | 150 000 | The base will fail to load when exceeding this limit. The limit can be modified in `dtable_server_config.json`/through the `BASE_MAX_ROWS_LIMIT` environment variable. |
| | Archived rows | no limit | |
| | Tables | 200 | |
| | External links for bases | 100 | |
| | External links for views | 100 | |
| | Apps | 100 | |
| | Forms | 100 | |
| Tables | Columns | 500 | |
| External links | External link viewing rate | 300/min | |
| Import / export | Size of a base being exported as a DTABLE file | 100MB | All files stored in a base can be viewed and deleted via File Management. The limit can be modified in dtable_web_settings.py (`DTABLE_EXPORT_MAX_SIZE`). |
| | Import of a XLSX/CSV file | 50 000 records or 10MB | |
| | Export of a table | 10 000 records or 1,000,000 cells | |
| | Export of a view in table | 1 000 000 cells | |
| Import / export big data | Import from XLSX to big data storage | 500 000 records or 40MB | The row limit can be modified in dtable_web_settings.py (`BIG_DATA_ROW_IMPORT_LIMIT`). The file size limit cannot be configured. |
| | Update from XLSX to big data storage | 500 000 records or 40MB | The row limit can be modified in dtable_web_settings.py (`BIG_DATA_ROW_UPDATE_LIMIT`). The file size limit cannot be configured. |
| | Export big data view to Excel | 250 000 records | The limit can be modified in dtable_web_settings.py (`ARCHIVE_VIEW_EXPORT_ROW_LIMIT`). |
| Groups | Group members | 500 | The limit can be modified in dtable_web_settings.py (`GROUP_MEMBER_LIMIT`). |
| | Group bases | 500 | |
| Common datasets (CDS) | Syncs of CDS | Sync up to the first 50 000 records | |
| | Sync frequency | 5 minutes | The limit can be modified in dtable_web_settings.py (`SYNC_COMMON_DATASET_INTERVAL`). |
| Automation rules | Records meet specific conditions after modification | For batch modification, check the first 50 records. A rule can be triggered up to 10 times per minute. | |
| | Add record | For batch addition, check the first 50 records. A rule can be triggered up to 10 times per minute. | |
| | Run periodically on records meet conditions | Lock a maximum of 200 rows and send a maximum of 50 emails in one trigger | |
---
Source: https://admin.seatable.com/introduction/editions/
# SeaTable Server Editions
There are two editions of SeaTable Server available for self hosting.
- **Enterprise Edition**: The full-featured edition with advanced permissions, custom roles, Big Data archiving, and enterprise authentication. Requires a license (free for up to 3 users).
- **Developer Edition**: For developers and small teams using SeaTable as a database backend via APIs and scripts. No license required, but limited to 200 concurrent connections to dtable-server and without enterprise features.
## Feature comparison
| Feature | Developer | Enterprise |
|---|:---:|:---:|
| Storage, rows, API calls | Unlimited | Unlimited |
| Concurrent connections (dtable-server) | 200 | Unlimited |
| Advanced permissions (column/row level) | - | Yes |
| Advanced customization | - | Yes |
| External apps | - | Yes |
| Row archiving (Big Data) | - | Yes |
| Custom user roles & quotas | - | Yes |
| Custom admin roles | - | Yes |
| Universal App (HTML pages) | - | Yes |
| Prometheus metrics endpoint | - | Yes |
| License required | No | Yes (free for up to 3 users) |
| SaaS usage permitted | No | No |
## License and limitation of SeaTable Developer Edition
The services of SeaTable Server (both editions) are released under the following licenses:
- dtable-web: Apache License v2
- dtable-events: Apache License v2
- dtable-server: [Proprietary License](dtable-server-license.md)
- seaf-server: AGPLv3
SeaTable developer edition should not be used to provide SaaS service or as a part of your SaaS service. Other kinds of usage are okay, including
- Personal or home use
- Internal in-house use
- Collaboration with customers
- IT projects for customers, as long as a separate server is used for each customer
## License and limitations of SeaTable Enterprise Edition
The SeaTable Enterprise Edition is released under a proprietary license. You find the EULA at .
---
Source: https://admin.seatable.com/introduction/dtable-server-license/
End User License Agreement for dtable-server
Version: September 2020
## 1. Parties and Subject Matter
1. The provisions of this End User License Agreement ("EULA") govern the relationship between Seafile Ltd., GuiGuLiangCheng, Block 2B, #310, HaiDian District, Beijing, China ("Seafile") and end users ("End Users") (collectively the "Parties") with respect to the licensing by Seafile of the software dtable-server ("Server" or "Software").
2. A License Agreement between the Parties pursuant to this EULA is concluded when the End User downloads the Server, alone or bundled with other software. IF YOU DO NOT AGREE TO THIS EULA, DO NOT DOWNLOAD, INSTALL AND USE THE SERVER. The same applies for the software with which the Server is bundled.
## 2. Changes to the EULA
Seafile is entitled to amend this EULA. SeaTable posts the amended EULA on the website https://seatable.com no less than two months before it becomes effective. The End User is therefore advised to visit this EULA regularly and to check for amendments. IF YOU DO NOT AGREE TO THE AMENDED EULA, QUIT USING THE SERVER AND UNINSTALL IT. The same applies for the software with which the Server is bundled.
## 3. Product Specification, Availability and Updates
1. The Server is a software developed by Seafile. Its functions and its requirements are described on the website https://seatable.com; technical details are provided in the administrator manual. The Server can be used free of charge.
2. The Server is made available to the End User by download, bundled with other software in the form of the application SeaTable Community Edition ("SeaTable CE"), of which the Server is a key component and without which SeaTable CE is not functional. This applies for installation media as well as updates.
3. The End User is responsible for installation and configuration. Seafile does not offer any kind of support for the Server nor has the End User any claim. Seafile and its affiliates operate a Community Forum at https://forum.seatable.com where End Users can help one another.
4. Seafile will regularly release new versions of the Server. At its sole discretion, it may add/modify/remove functions and features and/or supported platforms. Seafile informs about new releases and associated changes on its blog and in the Community Forum.
5. Seafile may also decide, at its discretion, to discontinue the development of the Server.
6. Some functions and features of the Server may depend on third-party products and services, all of which may be subject to changes. As a consequence, Seafile may need to modify or limit functions and features of the Server.
## 5. Rights of Use
1. Seafile grants to the End User the non-exclusive, non-transferable and non-sublicensable right to install, run and use the Server to the extent granted by this EULA.
2. The rights of use, granted under this EULA, are unlimited in time as long as the End User agrees to this EULA.
3. Any use of the Server beyond the scope granted under this EULA is prohibited and may be prosecuted.
4. The rights of use, granted pursuant to this EULA, do not include any rights to the source code of the Server.
5. The rights, granted pursuant to this EULA, do not include and the End User is not entitled to and shall not allow a third party to
(I) attempt to circumvent any technical measures and devices of the Server that are directed at, or have the effect of, enforcing this EULA and its terms;
(II) modify, create derivative works, translate, decompile or create or attempt to create, by reverse engineering or otherwise, the source code of the Server;
(III) remove, modify or obscure any copyright, trademark, service mark or other proprietary rights, confidentiality, serial number, notice, legend or similar on any copy of the Server, or related data, manuals, documentation or other materials;
(IV) market, sell, lend, rent, lease or distribute the Server;
(V) use the Server, on its own or as a part of another product and irrespective of the delivery model, for creating or providing a commercial service or a free public or de-facto public service; and
(VI) assign, sublicense or otherwise transfer any rights in or to the Server.
6. Seafile retains all right, title and interest in and to the Server (and any new versions thereof provided by Seafile) and in all copies, modifications and derivative works of the Server including, without limitation, all rights to patent, copyright, trade secret, trademark and other proprietary or intellectual property rights.
## 6. Documentation and Interfaces
1. Seafile and its affiliates provide an online user and administrator manual in English on the website https://seatable.com. Any further languages may be offered by Seafile on a voluntary basis.
2. Seafile retains all right, title and interest in and to such documentation and in all copies, modifications and derivative works thereof.
3. The Server may, at Seafile's sole discretion, provide application programming interfaces or other software interfaces (collectively "API") that allow third-party or customer applications to communicate with the Server (collectively "third-party software"). Seafile may change or discontinue APIs at any time without any obligation or liability to the End User. The respective provider is responsible for the third-party software. The provisions of the EULA do not apply to any such third-party software. Under no circumstances is Seafile liable for any third-party software.
## 7. Obligations and Duties of the End User
1. The End User is obliged to use the Server only in accordance with the provisions of this EULA and in accordance with laws and regulations applicable to such use and may not infringe on any third-party rights in connection with such use. The End User must, in particular, comply with all applicable data protection and export control provisions.
2. The requirements for the Server are specified in the administrator manual. The End User familiarizes himself/herself with these requirements prior to download, installation and use of the Server.
3. The End User reports errors and bugs ("Defects") on the Community Forum. The report of any Defect must include
* a detailed description of the defect,
* instructions to reproduce it,
* the relevant logs,
* the Software's version and
* the operating system and version.
If a Defect occurred when accessing the Software via a browser, the report must additionally include
* browser type and version,
* screenshots of the defect and
* the content of browser console.
## 8. Data Privacy
1. Seafile collects, processes and uses personal data of the End User as described in detail in the Privacy Statement.
2. Non-personal or anonymous data may be collected automatically to improve functionality and the user experience with the Server. The End User agrees that Seafile owns all rights in, and is free to use any such non-personal or anonymous data in any way it deems fit for development, diagnostic, corrective as well as marketing or any other purposes.
## 9. Limitation of Liability
IN NO EVENT, UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, WILL SEAFILE BE LIABLE TO END USERS FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THE END USER OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SEAFILE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
## 10. Warranty Claims
THERE IS NO WARRANTY FOR THE SERVER, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH THE END USER. SHOULD THE PROGRAM PROVE DEFECTIVE, THE END USER ASSUMES THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
## 11. Final Provisions
1. Any notifications and declarations in connection with the EULA will be made through public announcements on the website https://seatable.com and/or the Community Forum at https://forum.seatable.com. The End User is responsible for checking these two sites regularly.
2. The EULA and any disputes in connection with it are solely governed by, and construed in accordance with, the law of the People's Republic of China.
3. The exclusive place of jurisdiction is Beijing, China. Seafile reserves the right to sue at the End User’s head office.
4. If a provision of the EULA is found to be partly or wholly invalid or unenforceable, this shall not affect the validity and enforceability of the remaining provisions of the EULA. In place of the invalid or unenforceable provision, a valid and enforceable provision shall apply which reflects as closely as possible the commercial intention of the parties as regards the invalid or unenforceable provision.
---
Source: https://admin.seatable.com/introduction/get-support/
# Get support
Next to this administration manual there are more documentations available. To learn more about how to use SeaTable as a user, how to use the SeaTable API, the possibilities to develop your own plugins or scripts in SeaTable, please refer to their respective manuals:
- [SeaTable User Manual](https://seatable.com/help/)
- [SeaTable Developer Manual](https://developer.seatable.com)
- [SeaTable API Reference](https://api.seatable.com)
See the [official SeaTable channel](https://www.youtube.com/seatable) on YouTube for tutorials, guides and overviews. Visit [our blog](https://seatable.com/blog/) for latest news and to learn more about what is going on in and around SeaTable.
At any time you could have a look at the SeaTable [Community Forum](https://forum.seatable.com) to share your experience with other users or report issues or bugs.
If you're using SeaTable in your organization and need
assistance, e.g., to __digitalization of processes__, __develop custom solutions__ or __improve efficiency__,
[__get in touch__](mailto:sales@seatable.io) to discuss our __enterprise support__ offerings.
We're happy to help!
---
Source: https://admin.seatable.com/introduction/server-changelog/
# SeaTable Changelog
SeaTable, as a dynamic platform, undergoes frequent updates and enhancements to provide users with the best possible experience. To keep our users informed about these changes, we maintain several changelogs:
## Functions
For a comprehensive overview of updates to the SeaTable Server, users can refer to our detailed changelog available at [SeaTable Server Changelog](https://seatable.com/changelog/). Here, they can explore the latest features, improvements, and bug fixes implemented in each release, ensuring they stay up-to-date with the platform's evolution.
## Blog with Release Notes
In addition to the detailed changelogs mentioned above, we curate a blog featuring [release notes](https://seatable.com/blog/) that highlight the most significant changes in each version. This narrative-style format provides users with a concise yet informative overview of key updates, allowing them to quickly grasp the impactful enhancements introduced in a particular release. You can explore our blog at SeaTable Release Notes Blog.
## New API Calls
As the SeaTable API evolves to meet the changing needs of our users and developers, we document all new API calls and changes in our [API Changelog](https://api.seatable.com/reference/changelog). This resource, available at SeaTable API Changelog, provides developers with insights into the latest API updates, enabling them to leverage new functionalities and enhancements in their integrations and applications.
## Extra Upgrade Notices
In addition to general changelogs, we provide specific [upgrade notices](../upgrade/extra-upgrade-notice.md) containing changes relevant to administrators. These notices highlight critical updates, potential impact on system configurations, and any necessary actions to ensure smooth transitions during upgrades.
---
## Installation
Source: https://admin.seatable.com/installation/start/
# Introduction to SeaTable Server Installation
SeaTable is the world leading self hosted no-code platform. You can run SeaTable on consumer or enterprise-grade hardware and a variety of operating systems and architectures. The installation always uses Docker and the docker compose plugin. This guide outlines the installation process for SeaTable Server (Enterprise and Developer Edition) on a Linux OS using Docker.
Our goal is to offer a straightforward installation method that results in a fully operational SeaTable system accessible via HTTPS within minutes. While the steps have been tested on Debian and Ubuntu-based systems, they should also work on other Linux server systems. The installation is executed via the command line as the `root` user.
Before You Begin: [Review the requirements](../introduction/requirements.md).
You can deploy SeaTable-Server in one of the following topologies:
## Single-Node Deployment
- Easy installation with docker and docker compose.
- Ideal for testing purposes or smaller teams for up to 100 users.
[Start the installation](./basic-setup.md){ .md-button .md-button--primary } [Our deployment approach](./deployment-approach.md){ .md-button }
## Cluster Deployment
- Enterprise-grade high-performance no-code platform.
- Maximum performance and scalability for thousands of users.
[Read more about Cluster](./cluster/introduction.md){ .md-button }
---
Source: https://admin.seatable.com/installation/deployment-approach/
# Deployment Approach
A SeaTable Server consists of multiple containers. Therefore let's talk about how you typically install such a system.
## Multi-container installations can be intricate
Usually, software relying on multiple containers involves a large and complex `docker-compose.yml` file. This complexity intensifies with optional containers, leading to bloated files or the need to manually manage additional services. This is quite a challenging task.
In addition, consistently maintaining correct indentation and syntax alignment in the YAML file demands caution. In summary, this process can be cumbersome, prone to errors, and challenging—particularly for beginners or users unfamiliar with docker-compose files.
## We want to keep it simple ...
Instead of handling one extensive `docker-compose.yml` file, we present a more structured approach:
- We provide a set of individual yml files and one `.env` file.
- Each yml file defines commands for installing a specific component, such as the SeaTable Server, web proxy (caddy), or python pipeline.
- An accompanying `.env` file manages environment variables to configure your setup.
## Layered structure
Think of the `.env` file as a recipe for your setup and the yml files are like ingredients.
The default `.yml` files **should not be modified** since they will be overwritten during the [upgrade process](../upgrade/upgrade-manual.md).
However, if you wish to make alterations, read our guide on how to [customize your installation](../configuration/customizations.md) to ensure that version upgrades stay seamless.
You can configure components in the `.env` file, determining which ones to install. Start with essential components like SeaTable Server and Caddy web proxy.
Example in the `.env` file:
```bash
COMPOSE_FILE='caddy.yml,seatable-server.yml'
```
By adding or removing yml files from this list, you control the composition during runtime, eliminating the need for a single, extensive `docker-compose.yml` file.

With this understanding, the subsequent installation descriptions should be straightforward to follow.
Throughout the installation process, we strive to eliminate the need for manual file editing. Most commands can be executed by simply copying and pasting. Look for the copy-and-paste icon (:material-content-copy:) at the end of each code box, which conveniently copies the content to your clipboard. This helps prevent typing errors and ensures a smoother installation experience.
## Additional Components
Like the basic installation, the installation of the additional components will be easy and straight forward. Additional components are solutions that either extend the functionality of SeaTable or help you during your daily life.
These are the assumptions that we assume:
- Your SeaTable Basic Setup is up and running
- Your server is public reachable and you use a let's encrypt certificate
- Additional services are provided by port (and not by subdomain or subfolder)
- If you block incoming traffic with a firewall, you have to open some ports to make the solution reachable over the internet.
## Used Ports
This is the list of ports that the components use. You only have to open them if you want
- SeaTable: 80 and 443
- N8n: 6231
- Collabora: 6232
- OnlyOffice: 6233
- Uptime Kuma: 6230
- Zabbix: 6235
- Whiteboard (tldraw): 6239
- Report Design (seadoc): 6240
- Gatus Monitoring: 6220
- Dozzle Log Viewer: 6241
## Separate server or subdomain
This is possible for sure. Right now the installation follows the assumption from the top. You will find articles in the **Advanced Setup** explaining how to use custom certificates, custom domains or separate servers.
---
## Single-Node Deployment
Source: https://admin.seatable.com/installation/basic-setup/
# Single-Node installation of SeaTable Server
This manual will guide you through the process of installing a SeaTable Server instance with Caddy as proxy. By the end of it, you'll have a SeaTable Server instance that is accessible via HTTPS under your custom domain.
Watch a brief English video demonstrating all the essential steps:
:fontawesome-brands-youtube:{ style="color: #EE0F0F" }
__[How to install SeaTable within minutes]__ :octicons-clock-24: 10m
[How to install SeaTable within minutes]: https://www.youtube.com/watch?v=VJNcZK1BLHY
Most commands in this manual are provided in a way that you can copy and paste them into your command line. Simply click the (:material-content-copy:) icon in the top-right corner of the code boxes to copy the commands to the clipboard.
## Install basic tools
First things first, open a root shell on your server and install some basic tools that you'll need. Usually all these tools are already installed on your Linux server.
```bash
apt update && \
apt -y install curl pwgen tree wget tar nano
```
## Install Docker and Docker Compose Plugin
At [get.docker.com](https://get.docker.com), you find a script designed for the easy and convenient installation of the Docker Engine. While the script isn't recommended for production environments, it has shown no issues in our observations. You can effortlessly install Docker using this single command:
```bash
curl -fsSL get.docker.com | bash
```
Alternatively, you can opt to follow [Docker's official installation instructions](https://docs.docker.com/engine/install/).
## Install SeaTable Server
This installation assumes that all SeaTable components are installed under `/opt`.
We highly recommended to keep this folder structure. All articles in the SeaTable Admin Manual assume SeaTable's installation in this directory.
#### 1. Create basic structure
Create a directory `seatable-compose` in `/opt` and download the latest YML-files from the repository [:simple-github: seatable-release](https://github.com/seatable/seatable-release) into it.
```bash
mkdir /opt/seatable-compose && \
cd /opt/seatable-compose && \
wget -c https://github.com/seatable/seatable-release/releases/latest/download/seatable-compose.tar.gz \
-O - | tar -xz -C /opt/seatable-compose && \
cp -n .env-release .env
```
To get an overview of the downloaded files, use the `tree` command.
```bash
tree -a /opt/seatable-compose
```
The expected output should appear as follows.
```bash
# this should be the output of the tree command
/opt/seatable-compose
├── caddy.yml
├── clamav.yml
├── collabora.yml
├── .env
├── .env-release
...
├── python-pipeline.yml
├── restic.yml
├── seadoc.yml
├── seatable-server.yml
├── tldraw.yml
├── tools
├── uptime-kuma.yml
└── zabbix.yml
```
Generally, there's no need to make changes to the YML-files. Customizations should only be made by experienced Docker administrators.
Please read our guide that describes how the [configuration can be customized](../configuration/customizations.md).
This ensures that version upgrades stay seamless since the default `.yml` files are **overwritten with each upgrade**.
#### 2. Add secrets
SeaTable is configured with the hidden `.env` file (=environment configuration file) that is stored in the folder `/opt/seatable-compose`.
Now use the command line tool `pwgen` to create secure passwords for your _admin account_, the _database root password_, the _Redis_ instance and a secret for secure communication between the SeaTable components. The following commands will generate four such passwords and insert them in the `.env` file.
sed -i "s/^SEATABLE_ADMIN_PASSWORD=.*/SEATABLE_ADMIN_PASSWORD=$(pwgen 40 1)/" .env
sed -i "s/^MARIADB_PASSWORD=.*/MARIADB_PASSWORD=$(pwgen 40 1)/" .env
sed -i "s/^REDIS_PASSWORD=.*/REDIS_PASSWORD=$(pwgen 40 1)/" .env
sed -i "s/^JWT_PRIVATE_KEY=.*/JWT_PRIVATE_KEY=$(pwgen 40 1)/" .env
sed -i "s/^SECRET_KEY=.*/SECRET_KEY=$(pwgen 40 1)/" .env
Alternatively, you can manually add your own passwords.
When setting passwords manually (without `pwgen`), do **not** use special characters such as `%`, `#`, `$`, `&`, `'`, `"` or similar. These may cause issues with Python libraries during installation and can prevent your
SeaTable Server Docker container from leaving *unhealthy* mode.
Instead, choose a **long password** using uppercase, lowercase, and digits to ensure both compatibility and security. Alternatively, you can use `pwgen 40` to generate several secure 40-character passwords.
#### 3. Complete settings in the .env file
Open the `.env` file with the text editor of your choice, like `nano` or `vim`.
```bash
nano /opt/seatable-compose/.env
```
Continue setting up your SeaTable server by adjusting only three more variables. These are:
- TIME_ZONE
- SEATABLE_SERVER_HOSTNAME
- SEATABLE_ADMIN_EMAIL
=== "`.env` for SeaTable Server Enterprise Edition"
``` python
# components to be used
COMPOSE_FILE='caddy.yml,seatable-server.yml' # (1)!
COMPOSE_PATH_SEPARATOR=','
# system settings
TIME_ZONE='Europe/Berlin' # (2)!
# seatable server base url
SEATABLE_SERVER_HOSTNAME='seatable.example.com' # (3)!
SEATABLE_SERVER_PROTOCOL='https'
# initial web admin
SEATABLE_ADMIN_EMAIL='me@example.com'
SEATABLE_ADMIN_PASSWORD='topsecret'
# database
MARIADB_PASSWORD='alsotopsecret'
# redis
REDIS_PASSWORD='anotherverysecurepassword'
# shared secret for secure communication
JWT_PRIVATE_KEY='anothersecret'
SECRET_KEY='anothertopsecret'
```
1. COMPOSE_FILE is a comma-separated list **without spaces**. This list defines which components the server runs. Leave `caddy.yml` and `seatable-server.yml` at the beginning. You will add more components at a later time.
2. A [list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) is available on Wikipedia.
3. SEATABLE_SERVER_HOSTNAME is the (sub)domain (without http:// or https://) under which the server is accessible on (at least) port 80 and 443.
If you want to use a public IP address (e.g. 5.35.28.112), you can use the free service [nip.io](https://nip.io/). In this case, enter your your-ip.nip.io address (e.g. 5.35.28.112.nip.io).
If you want to use a local IP address (e.g. 192.168.178.10), please see section [Custom Certificates](./advanced/custom-certificates.md)
=== "`.env` for SeaTable Server Developer Edition"
To install the SeaTable Developer Edition instead of Enterprise edition, add the following parameter to your `.env` file. This overwrites the used SeaTable Docker image. **Everything else remains identical to the SeaTable Enterprise Edition.**
``` python
SEATABLE_IMAGE='seatable/seatable-developer:latest' # (1)!
```
1. Instead of latest you can select a concrete version from [https://hub.docker.com/r/seatable/seatable-developer/tags](https://hub.docker.com/r/seatable/seatable-developer/tags).
The variable values in the `.env` are strings. So they should be put in ' '.
#### 4. Get a license
SeaTable Enterprise requires a license to start.
You can use SeaTable Server Enterprise Edition for free with up to three users, but you must request and download a license file. The license file is valid for two years. You can generate a new license file at any time. If you want to use SeaTable Server Enterprise Edition with more than three users, [you can buy a (on-premises) license on seatable.com/prices](https://seatable.com/prices/).
Run the following command, replacing `me@example.com` with your valid email address. Shortly after, you'll receive an email with instructions to download your license to the current directory.
```bash
curl https://get.seatable.com/license/me@example.com
# ... follow the steps in the email ...
```
Your license should now be saved at `/opt/seatable-compose/seatable-license.txt`.
#### 5. Fire up the server
Now it is time to run the following command to download and initiate the docker images for the initial setup. This process will require some time.
```bash
docker compose up -d
```
If the initialization completes successfully, you can open your web browser and access your SeaTable Server instance using the URL specified in the `.env` file.
Sign in using the credentials you provided in the same file.
Caddy automatically obtains and renews Let's Encrypt certificates for the domain configured in your `.env` file. No manual certificate management is required. If you need to use custom certificates instead, see [Custom Certificates](./advanced/custom-certificates.md).
:partying_face: **Congratulations!** You've completed the basic setup of SeaTable Server.
## Next steps
Your SeaTable Server is running — here are the recommended next steps:
Before you start using SeaTable productively, make sure to set up a [backup procedure](../maintenance/backup-recovery.md). For single-node servers, the [Restic backup container](./components/restic.md) provides an easy automated solution.
- **Email**: Configure [email sending](../configuration/sending-email.md) so SeaTable can send notifications and password reset emails.
- **Plugins**: Install [plugins](../configuration/plugins.md) to enable additional views like Gallery, Map, or Kanban.
- **Components**: Expand functionality with the [Python Pipeline](./components/python-pipeline.md), [n8n](./components/n8n.md), or [office editors](./components/collabora.md).
- **Authentication**: Set up [Single Sign-On](../configuration/authentication/saml.md) or [LDAP](../configuration/authentication/ldap.md) for centralized user management.
- **Monitoring**: Add [Gatus](./components/gatus.md) or [Uptime Kuma](./components/uptime-kuma.md) to monitor your instance.
- **Troubleshooting**: Check the [FAQ](./faq.md) if you run into issues.
This manual covers everything from **advanced cluster installations** to detailed **configuration options**. If you can't find what you need, post in the [SeaTable community forum](https://forum.seatable.com) or contribute directly via pull request on GitHub.
---
Source: https://admin.seatable.com/installation/components/seatable-ai/
# SeaTable AI Integration
SeaTable AI is a SeaTable extension that integrates AI functionality into SeaTable.
Deploying SeaTable AI allows users to execute AI-based automation steps within SeaTable.
At the time of writing, the following types of automation steps are supported:
- **Summarize**
- **Classify**
- **OCR** (Optical character recognition)
- **Extract**
- **Custom** for individual use cases
## Deployment
The SeaTable AI container does not provide any AI functionality by itself. It only manages the connection between SeaTable and an external large language model (LLM) service. You can connect it to a commercial provider (e.g., OpenAI, Deepseek) or to a self-hosted LLM running on your own infrastructure.
The easiest way to deploy SeaTable AI is to deploy it on the same host as SeaTable Server. A standalone deployment (on a separate host or virtual machine) is explained [here](../advanced/seatable-ai-standalone.md).
### Amend the .env file
To install SeaTable AI, include `seatable-ai.yml` in the `COMPOSE_FILE` variable within your `.env` file. This instructs Docker-Compose to include the `seatable-ai` service.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,seatable-ai.yml'/" /opt/seatable-compose/.env
```
Then add SeaTable AI server configurations in `.env`:
```ini
ENABLE_SEATABLE_AI=true
```
### LLM Provider Configuration
SeaTable AI will use AI functions in conjunction with a Large Language Model (LLM) service.
SeaTable AI supports a wide variety of LLM providers through [LiteLLM](https://docs.litellm.ai/docs) as well as any LLM services with OpenAI-compatible endpoints. Please refer to [LiteLLM's documentation](https://docs.litellm.ai/docs/providers) in case you run into issues while trying to use a specific provider.
In order to ensure the efficient use of SeaTable AI features, you need to select a **large, multimodal model**.
This requires the chosen model to support image input and recognition (e.g. for running OCR as part of automations).
The following section showcases the required configuration settings for the most popular hosted LLM services.
The configuration approach depends on your SeaTable version:
#### SeaTable v6.0 + v6.1
For SeaTable v6.0 and v6.1, the LLM provider is configured inside the `.env` file:
=== "OpenAI"
```ini
SEATABLE_AI_LLM_TYPE=openai
SEATABLE_AI_LLM_KEY=
SEATABLE_AI_LLM_MODEL=gpt-4o-mini # recommended
```
=== "Deepseek"
```ini
SEATABLE_AI_LLM_TYPE=deepseek
SEATABLE_AI_LLM_KEY=
SEATABLE_AI_LLM_MODEL=deepseek-chat # recommended
```
=== "Azure OpenAI"
```ini
SEATABLE_AI_LLM_TYPE=azure
SEATABLE_AI_LLM_URL= # your deployment url, leave blank to use default endpoint
SEATABLE_AI_LLM_KEY=
SEATABLE_AI_LLM_MODEL=
```
=== "Gemini / Google AI Studio"
```ini
SEATABLE_AI_LLM_TYPE=gemini
# Leave SEATABLE_AI_LLM_URL unset
SEATABLE_AI_LLM_KEY=
SEATABLE_AI_LLM_MODEL=
```
=== "Ollama"
```ini
SEATABLE_AI_LLM_TYPE=ollama
SEATABLE_AI_LLM_URL=
SEATABLE_AI_LLM_KEY=
SEATABLE_AI_LLM_MODEL=
```
=== "HuggingFace"
```ini
SEATABLE_AI_LLM_TYPE=huggingface
SEATABLE_AI_LLM_URL=
SEATABLE_AI_LLM_KEY=
SEATABLE_AI_LLM_MODEL=/
```
=== "Self-Hosted Proxy Server"
```ini
SEATABLE_AI_LLM_TYPE=proxy
SEATABLE_AI_LLM_URL=
SEATABLE_AI_LLM_KEY= # optional
SEATABLE_AI_LLM_MODEL=
```
=== "Other"
If you are using an LLM service with ***OpenAI-compatible endpoints***, you should set `SEATABLE_AI_LLM_TYPE` to `other` or `openai`, and set other LLM configuration settings as necessary:
```ini
SEATABLE_AI_LLM_TYPE=...
SEATABLE_AI_LLM_URL=...
SEATABLE_AI_LLM_KEY=...
SEATABLE_AI_LLM_MODEL=...
```
#### SeaTable v6.2+
SeaTable v6.2 and later versions require you to configure the LLM provider inside the `/opt/seatable-server/seatable/conf/seatable_config.yaml` file **on the host**. The LLM provider configuration is now placed inside a `.yaml` file to allow configuring different providers/models for different AI functions.
If the file does not exist yet, simply create it.
=== "OpenAI"
```yaml
global:
LLM_MODELS:
- type: openai
key:
model: gpt-4o-mini # recommended
```
=== "Deepseek"
```yaml
global:
LLM_MODELS:
- type: deepseek
key:
model: deepseek-chat # recommended
```
=== "Azure OpenAI"
```yaml
global:
LLM_MODELS:
- type: azure
url: # your deployment url, leave blank to use default endpoint
key:
model:
```
=== "Gemini / Google AI Studio"
```yaml
global:
LLM_MODELS:
- type: gemini
key:
model:
```
=== "Ollama"
```yaml
global:
LLM_MODELS:
- type: ollama
url:
key:
model:
```
=== "HuggingFace"
```yaml
global:
LLM_MODELS:
- type: huggingface
url:
key:
model: /
```
=== "Infomaniak"
```yaml
global:
LLM_MODELS:
- type: openai
# You can get the product ID from the Infomaniak API
# https://developer.infomaniak.com/docs/api/get/1/ai
url: https://api.infomaniak.com/2/ai/{PRODUCT_ID}/openai/v1
key:
model:
```
=== "Self-Hosted Proxy Server"
```yaml
global:
LLM_MODELS:
- type: proxy
url:
key: # optional
model:
```
=== "Other"
If you are using an LLM service with ***OpenAI-compatible endpoints***, you should set `type` to `other` or `openai`, and set other LLM configuration settings as necessary:
```yaml
global:
LLM_MODELS:
- type: ...
url: ...
key: ...
model: ...
```
The `seatable-ai` container will **not** be automatically restarted when running `docker compose up -d` if you've only made changes to the `seatable_config.yaml` config file.
Docker Compose does not watch files inside volume mounts, therefore a manual recreation of the container (via `--force-recreate`) is necessary whenever you're making configuration changes:
```bash
cd /opt/seatable-compose
docker compose up -d --force-recreate seatable-ai
```
##### Multiple LLM Providers
Since version 6.2, SeaTable AI supports the configuration of multiple LLM providers for different purposes.
Simply configure multiple providers under `global.LLM_MODELS` within `seatable_config.yaml`.
The following `seatable_config.yaml` example configures two LLM providers:
- A self-hosted model (using vLLM) with `tier: low`
- A hosted Mistral model is used for more complex tasks (`tier: high`)
The second block (`seatable-ai.FEATURE_MODEL_TIER`) is used to configure the required tier level for each AI functionality.
In this example, the configuration ensures that the self-hosted model is used for OCR, text summarization, classification and extraction tasks,
while the cloud-hosted Mistral model will be used for custom prompts.
```yaml
global:
LLM_MODELS:
- type: hosted_vllm
model:
tier: low
url:
key:
- type: mistral
model:
tier: high
key:
seatable-ai:
FEATURE_MODEL_TIER:
ocr: low
text_summarize: low
classification: low
extract: low
custom: high
```
`tier` supports the following values: `low`, `medium` and `high`
### LLM Timeout Configuration (Optional)
You can configure the communication timeout with the LLM service by specifying `SEATABLE_AI_LLM_TIMEOUT` in `.env` (the default is 180 seconds):
```ini
SEATABLE_AI_LLM_TIMEOUT=180
```
### Download SeaTable AI image and restart
One more step is necessary to download the SeaTable AI image and restart the SeaTable service:
```bash
cd /opt/seatable-compose
docker compose up -d
```
Now SeaTable AI can be used.
---
Source: https://admin.seatable.com/installation/components/html-server/
# HTML Server
The HTML Server component is required in order to render custom HTML pages inside universal apps.
## Deployment
The easiest way to deploy the HTML Server is to deploy it on the same host as SeaTable Server.
### Amend the .env file
To install the HTML Server, include `seatable-html-server.yml` in the `COMPOSE_FILE` variable within your `.env` file.
This instructs Docker-Compose to include the `seatable-html-server` service.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,seatable-html-server.yml'/" /opt/seatable-compose/.env
```
### SeaTable Server Configuration
In order to enable the HTML page type within universal apps, the following configuration settings must be placed inside `/opt/seatable-server/seatable/conf/dtable_web_settings.py` on the host.
Simply replace `YOUR_SEATABLE_DOMAIN` with your hostname:
```python
ENABLE_UNIVERSAL_APP_HTML_PAGES = True
DTABLE_HTML_PAGES_SERVER_URL = 'https://YOUR_SEATABLE_DOMAIN/app-server/'
```
Do not forget to apply the configuration changes by restarting the `seatable-server` container:
```bash
docker compose restart seatable-server
```
### S3 Configuration
This step is only necessary in case you have configured the [S3 backend](../advanced/s3.md) for files and pictures.
Since the HTML Server component directly accesses these buckets, it needs access to the S3 credentials.
Create `custom-seatable-html-server.yml` with the following contents to add the required environment variables to the `seatable-html-server` service:
```yaml
services:
seatable-html-server:
environment:
- SEAF_SERVER_STORAGE_TYPE=s3
- S3_COMMIT_BUCKET=${S3_COMMIT_BUCKET:?Variable is not set or empty}
- S3_FS_BUCKET=${S3_FS_BUCKET:?Variable is not set or empty}
- S3_BLOCK_BUCKET=${S3_BLOCK_BUCKET:?Variable is not set or empty}
- S3_KEY_ID=${S3_KEY_ID:?Variable is not set or empty}
- S3_SECRET_KEY=${S3_SECRET_KEY:?Variable is not set or empty}
- S3_USE_V4_SIGNATURE=${S3_USE_V4_SIGNATURE:-true}
- S3_AWS_REGION=${S3_AWS_REGION:-us-east-1}
- S3_HOST=${S3_HOST:-}
- S3_USE_HTTPS=${S3_USE_HTTPS:-true}
- S3_PATH_STYLE_REQUEST=${S3_PATH_STYLE_REQUEST:-false}
- S3_SSE_C_KEY=${S3_SSE_C_KEY:-}
```
Then, simply add `custom-seatable-html-server.yml` to the `COMPOSE_FILE` variable inside your `.env` file.
### Start HTML Server
One more step is necessary to download the Docker image for the HTML Server and start the container:
```bash
cd /opt/seatable-compose
docker compose up -d
```
Now custom app pages can be created within universal apps.
---
Source: https://admin.seatable.com/installation/components/python-pipeline/
# Python Pipeline
To run Python scripts directly within SeaTable, you need to install the Python Pipeline — an environment utilizing Docker containers for script execution and result retrieval. Thanks to SeaTable's Python API, querying and manipulating data in a SeaTable base is super easy.
Explore various use cases from other SeaTable users:
- Retrieve current stock prices and store them in SeaTable.
- Validate DNS settings of specified domains for specific TXT entries.
- Capture submissions from [Jotform](https://www.jotform.com/) or [tally](https://tally.so/) and store the results.
- Identify duplicate entries and apply specific tags.
Find additional Python functions and code examples in the [SeaTable Developer Manual](https://developer.seatable.com).

## Installation
This how-to explains the deployment of the Python Pipeline next to your SeaTable Server instance.
If you allow untrusted users or users with limited trust to execute Python scripts within SeaTable, you should deploy the Python Pipeline on a separate node without private network access to your SeaTable server instance.
Please follow the [documentation](../advanced/python-pipeline-dedicated-server.md) on how to achieve this.
Python scripts run as user-supplied code with outbound network access. On a cloud VM (Azure, AWS, GCP and others) a script can therefore reach the instance metadata endpoint at `169.254.169.254` and request the host's machine-identity credentials — for example an **Azure Managed Identity** or an **AWS instance profile**. If that identity has any permissions attached, a script author can use the obtained tokens to access your cloud resources.
Until you apply a network-level block, protect your deployment as follows:
- **Do not attach a privileged machine identity** to the VM hosting the Python Pipeline. Remove it if it is not needed, or keep it strictly least-privilege (no role assignments beyond the minimum).
- Run the Python Pipeline on a [dedicated server](../advanced/python-pipeline-dedicated-server.md) so a script cannot reach unrelated workloads or identities.
- **AWS only:** require IMDSv2 and set the metadata hop limit to `1` (`aws ec2 modify-instance-metadata-options --http-tokens required --http-put-response-hop-limit 1`). This blocks bridged containers automatically. Azure has no hop-limit equivalent.
- To block reachability directly, drop egress to the metadata IP for the runner bridge on the host, e.g. `iptables -I DOCKER-USER -i br-runner -d 169.254.169.254/32 -j DROP` (scope the rule to the runner bridge — never block `169.254.169.254` host-wide, as the host itself relies on it).
#### Amend the .env file
To install the Python Pipeline, append `python-pipeline.yml` to the `COMPOSE_FILE` variable within your `.env` file. This instructs Docker to download the required images for the Python Pipeline.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,python-pipeline.yml'/" /opt/seatable-compose/.env
```
When manually adding `python-pipeline.yml` to the `COMPOSE_FILE` variable using your preferred text editor, make sure that you do not enter a space (:material-keyboard-space:). After the modification, your `COMPOSE_FILE` variable should look like this:
```bash
COMPOSE_FILE='caddy.yml,seatable-server.yml,python-pipeline.yml'
```
#### Generate a shared secret for secure communication
For secure communication between SeaTable and the Python Pipeline, a shared secret is required to prevent unauthorized access or usage. We recommend utilizing `pwgen` to generate a robust and secure password. Copy and paste the following command into your command line to generate a password:
```bash
pw=$(pwgen -s 40 1) && echo "Generated shared secret: ${pw}"
```
The generated shared secret needs to be added to your `.env` file. Copy and paste the following command:
```bash
echo -e "\n# python-pipeline" >> /opt/seatable-compose/.env
echo "ENABLE_PYTHON_SCRIPT=true" >> /opt/seatable-compose/.env
echo "PYTHON_SCHEDULER_AUTH_TOKEN=${pw}" >> /opt/seatable-compose/.env
```
#### Start the Python Pipeline
Now it is time to start the Python Pipeline.
```bash
cd /opt/seatable-compose && \
docker stop seatable-server && \
docker compose up -d
```
#### Check the functionality Python Pipeline
Do you want to execute your first Python script in SeaTable? Nothing easier than that.
- Login to your SeaTable Server.
- Create a new base and open it.
- Add a Python script with the content `print("Hello World")` and execute it. If you don't know how to do this, check out our [user manual](https://seatable.com/help/create-delete-script-seatable).
If everything went well, you should see the output `Hello World`.

:material-party-popper: **Great!** Your SeaTable Server instance can now run Python scripts.
---
Source: https://admin.seatable.com/installation/components/whiteboard/
# Whiteboard (tldraw)
SeaTable's whiteboard plugin offers a versatile platform for capturing thoughts and data, independent of base data. This plugin utilizes the [tldraw SDK](https://tldraw.dev) and requires special installation steps, including server-side components for collaborative drawing.

## Installation Requirements
1. SeaTable Enterprise Edition installed and running
2. Firewall configured to allow traffic on port 6239
3. System admin to install both the whiteboard plugin and the tldraw worker (server component)
## tldraw-worker Installation
Follow these steps to deploy the tldraw worker on the same node as the seatable-server:
#### Update .env file
Like with all additional components you need to add `tldraw.yml` to the `COMPOSE_FILE` variable in your `.env` file.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,tldraw.yml'/" /opt/seatable-compose/.env
```
#### Launch the worker
Start the `tldraw-worker`:
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
#### Verify Installation
After a few seconds, check `https://:6239/ping`. You should see:
```json
{"status":"pong"}
```
This confirms that the `tldraw-worker` is operational. If you don't see this message, check that port 6239 is allowed and the container logs.
## Final Steps
With the server-side installation complete, you can now install the **whiteboard plugin** through the SeaTable admin interface and begin using this creative tool.
---
## Advanced Configuration
### Custom Certificate
You need to make some changes to your `tldraw-worker` deployment in case your SeaTable server uses an internal CA.
It is not recommended to make changes to the provided `tldraw.yml` file.
You should copy `tldraw.yml` to `custom-tldraw.yml` and reference this file in your `.env` file instead.
The following changes need to be made in order to use an internal CA:
```yaml
services:
tldraw-worker:
# ...
environment:
# ...
# Configure Extra CA (chain) for node.js
- NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/MY-CA.pem
volumes:
# Mount the CA file into the container
- ./MY-CA.pem:/usr/local/share/ca-certificates/MY-CA.pem:ro
```
### Subfolder Installation
Deploying the tldraw-worker using a subfolder (e.g. `/tldraw`) instead of port 6239 is **not yet supported**.
You can refer to the following forum post for details regarding the required changes in your reverse proxy and the whiteboard plugin itself: [forum.seatable.com/t/configuring-new-whiteboard-plugin-tldraw/6482](https://forum.seatable.com/t/configuring-new-whiteboard-plugin-tldraw/6482)
---
Source: https://admin.seatable.com/installation/components/n8n/
# Automation platform n8n
SeaTable empowers users and teams to store, manage, and visualize structured data efficiently, offering multiple data input options from manual entry to web forms and a comprehensive API. This flexibility ensures seamless data collection while allowing users to define automated workflows with triggers and actions.
However, for those seeking additional software solutions or more sophisticated automation workflows, n8n provides the perfect complement. By integrating SeaTable with n8n, users can unlock even more powerful automation capabilities.
n8n serves as an automation platform, enabling seamless connectivity between SeaTable and hundreds of other software products. Need to collect data from multistep web forms using JotForm, Typeform, or Form.io? No problem. Simply create your web forms and utilize n8n to seamlessly transfer survey results to SeaTable.
Give [n8n](https://n8n.io) a try, and we guarantee you'll fall in love with it just like we have! :heart:
Watch a brief English video demonstrating all the essential steps:
:fontawesome-brands-youtube:{ style="color: #EE0F0F" }
__[Easy n8n Installation on SeaTable]__ :octicons-clock-24: 10m
[Easy n8n Installation on SeaTable]: https://www.youtube.com/watch?v=_mkA410VDT4
## Installation
This article shows you how to install **n8n** (Community Edition) on your SeaTable server.
This deployment does not include any [external task runners](https://docs.n8n.io/hosting/configuration/task-runners/).
These allow executing user-provided JavaScript and Python code within n8n workflows.
Please refer to the [n8n docs](https://docs.n8n.io/hosting/configuration/task-runners/) for instructions on how to deploy external task runners.
#### Change the .env file
Like with all additional components you first have to add the `n8n.yml` to the `COMPOSE_FILE` variable in your `.env` file.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,n8n.yml'/" /opt/seatable-compose/.env
```
#### Generate secrets for your postgres database
Now let's create initial secrets and write them into the .env file.
```bash
echo -e "\n# n8n" >> /opt/seatable-compose/.env
echo "N8N_ENCRYPTION_KEY=$(pwgen -s 40 1)" >> /opt/seatable-compose/.env
echo "POSTGRES_PASSWORD=$(pwgen -s 40 1)" >> /opt/seatable-compose/.env
echo "POSTGRES_NON_ROOT_PASSWORD=$(pwgen -s 40 1)" >> /opt/seatable-compose/.env
```
#### Start n8n
Now it is time to start n8n for the first time.
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
**Congratulations!** Your n8n server is ready to use.
## Initial setup
#### Create initial admin user
To set up your initial admin user, n8n offers a convenient Web UI accessible at `https://:6231`.

Please note that the Community Edition of n8n only permits the creation of multiple accounts with just one admin account. Further details regarding the features of this version will be elaborated later in this article.
## Limitations of the Community Edition of n8n
The installed n8n version on this server is the self-hosted free Community Edition, which aligns with the **Starter Cloud version**.
It offers:
- Unlimited executions
- Unlimited active workflows
- No execution time limit
- Support for all existing nodes
However, there are some limitations to be aware of:
- Only one admin account is allowed
- Variables are not supported (consider using SeaTable instead)
- External Secrets and Environments are not supported
- Single Sign-On (SSO) and LDAP is not supported
- Log Streaming is not supported
For further information, visit the [n8n forum](https://community.n8n.io/t/feedback-self-hosted-pricing/22727/56).
If you find n8n useful (which you most likely will), consider [purchasing an Enterprise license](https://n8n.io/pricing/).
## Next steps
Create your first workflow in n8n, add your first node and search for `SeaTable`. Currently SeaTable supports three triggers and 16 actions.
Alternatively check the docs of n8n at [https://docs.n8n.io/](https://docs.n8n.io/) for more details or do their [text courses](https://docs.n8n.io/courses/) to get a better understanding of n8n.
---
Source: https://admin.seatable.com/installation/components/seadoc/
# Report Design (seadoc)
SeaDoc is a Docker container required for the new SeaTable **Report Design** plugin. With this plugin, you can easily create multi-page technical reports, summaries, and other documents.
The **Report Design** plugin is currently in beta. We welcome your feedback. The official release is planned for version 6.0.
## Installation Requirements
1. SeaTable Enterprise Edition installed and running
2. Firewall configured to allow traffic on port 6240
3. System admin to install both the report design plugin and this seadoc editor (server component)
## SeaDoc Installation
Follow these steps to deploy the seadoc editor on the same node as the seatable-server:
#### Update .env file
Like with all additional components you need to add `seadoc.yml` to the `COMPOSE_FILE` variable in your `.env` file.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,seadoc.yml'/" /opt/seatable-compose/.env
```
#### Launch the seadoc editor
Simply run the following commands to (re-)start SeaTable and seadoc container.
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
#### Verify Installation
After a few seconds, check `https://:6240`. You should see:
```text
Welcome to sdoc-server. The current version is ...
```
This confirms that the `seadoc` container is operational. If you don't see this message, check that port 6240 is allowed and the container logs.
## Final Steps
With the server-side installation finished, you can now install the **report design plugin** from the SeaTable admin interface and start using this powerful reporting tool.
---
## Office Editors
Source: https://admin.seatable.com/installation/components/collabora/
# Collabora Online
Collabora Online offers real-time collaboration with office documents in your browser. As soon as you open a file from SeaTable, Collabora opens in a new browser tab and allows real time collaboration. As soon as the last user exits the document by closing his browser window, the document is saved back to the SeaTable base.
This article is about the how to install the CODE version of collabora online.
Collabora and OnlyOffice are both office editors. You have to decide which one you would like to use. You can not use both in parallel.
Collabora Online (CODE) can be installed on the same host as SeaTable Enterprise Edition. If Collabora Online is used regularly and by many users, the host should be fitted with sufficient cores and RAM or you should install Collabora on a separate host.
This manual assumes that SeaTable Enterprise Edition is installed and is running.
## Installation
#### 1. Change the .env file
To install Collabora, include `collabora.yml` in the `COMPOSE_FILE` variable within your `.env` file. This instructs Docker to download the required images for Collabora.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,collabora.yml'/" /opt/seatable-compose/.env
```
#### Modify dtable_web_settings.py
Now execute the following command to add the required configuration to `dtable_web_settings.py`. You don't have to replace `${SEATABLE_SERVER_HOSTNAME}`. It will replaced automatically.
```bash
source /opt/seatable-compose/.env
echo -e "\n# collabora online" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
echo "ENABLE_COLLABORA = True" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
echo "COLLABORA_DISCOVERY_URL = 'https://${SEATABLE_SERVER_HOSTNAME}:6232/hosting/discovery'" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
```
#### Download collabora and restart
One more step is necessary to download the Collabora container and restart the SeaTable service.
```bash
cd /opt/seatable-compose
docker compose down
docker compose up -d
```
## Check if installation is complete
Wait for some seconds and then open `https://:6232` and you should see simple an **OK**. This confirms that Collabora Online is up and running. Office documents that you double click in your base should be opened with Collabora Online in a new browser tab.
## Advanced: Custom settings
### Admin interface
Collabora Online provides an admin interface, which is disabled by default.
Add the following parameters to your `.env` file to activate it and adapt it to your needs.
```bash
COLLABORA_ADMIN=username
COLLABORA_PW=password
COLLABORA_ENABLE_ADMIN_CONSOLE=true
```
After restarting the Collabora container you can access the admin interface at `https://:6232/browser/dist/admin/admin.html`.
### Activate File Logging
To activate File logging of Collabora Online you have to add the following parameter to your `.env` file:
```bash
COLLABORA_ENABLE_FILE_LOGGING=true
```
After a restart of the container the logs are written to `/opt/cool/logs/coolwsd.log`. To access this log file at the host system you have to create a folder and change the permission to 777.
```bash
mkdir /opt/collabora
chmod 777 /opt/collabora
```
Now create a `custom-collabora.yml` file with the following volume definition:
```yaml
services:
collabora:
volumes:
- "${COLLABORA_PATH:-/opt/collabora}/logs:/opt/cool/logs/"
```
Specifying this override in a separate file and adding `custom-collabora.yml` to the `COMPOSE_FILE` variable inside your `.env` file ensures that your modifications are preserved across version upgrades of SeaTable.
You can read our [guide](../../configuration/customizations.md) for more information regarding this mechanism.
## Advanced: Collabora on a separate host and URL
### Install Collabora
Use the predefined yml files to install Collabora on a separate host. Your `.env` might look like
```bash
COMPOSE_FILE='caddy.yml,collabora.yml'
COMPOSE_PATH_SEPARATOR=','
SEATABLE_SERVER_HOSTNAME=
COLLABORA_PORT=443
```
You'll also have to add an additional `custom-collabora.yml` file that contains the following override:
```yaml
services:
collabora:
environment:
# Comma-separated list of domains that can access Collabora, e.g. https://cloud.seatable.io
- aliasgroup1=""
```
Remember to add this `custom-collabora.yml` file to the `COMPOSE_FILE` variable.
### Configuration of SeaTable server
Now update the `dtable_web_settings.py` on your SeaTable Server.
You'll also have to configure the `COLLABORA_HOSTNAME` variable inside your `.env` file.
This will cause the `Content-Security-Policy` header returned by Caddy to contain the correct values for the Collabora hostname.
---
Source: https://admin.seatable.com/installation/components/onlyoffice/
# Deploy ONLYOFFICE Documentserver
OnlyOffice offers real-time collaboration with office documents in your browser. As soon as you open a file from SeaTable, OnlyOffice opens in a new browser tab and allows real time collaboration. As soon as the last user exits the document by closing his browser window, the document is saved back to the SeaTable base.
Access takes place via the public URL via HTTPS. So that OnlyOffice cannot be used by other systems, a shared secret in the form of a JWT key is used.
Collabora and OnlyOffice are both office editors. You have to decide which one you would like to use. You can not use both in parallel.
OnlyOffice can be installed on the same host as SeaTable Enterprise Edition. If OnlyOffice is used regularly and by many users, the host should be fitted with sufficient cores and RAM or you should move OnlyOffice to a separate host.
This article assumes that SeaTable Enterprise Edition is installed and is running.
## Installation
#### Change the .env file
To install OnlyOffice, include `onlyoffice.yml` in the `COMPOSE_FILE` variable within your `.env` file. This instructs Docker to download the required images for OnlyOffice.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,onlyoffice.yml'/" /opt/seatable-compose/.env
```
#### Generate JWT-Token (shared secret)
Secure communication between SeaTable and OnlyOffice is granted by a shared secret.
Copy and paste the following commands to generate the shared secret and write it at the end of the `.env` file:
echo -e "\n# OnlyOffice" >> /opt/seatable-compose/.env
echo "ONLYOFFICE_JWT_SECRET=$(pwgen -s 40 1)" >> /opt/seatable-compose/.env
#### Modify dtable_web_settings.py
Now execute the following command to add the required configuration to `dtable_web_settings.py`.
```python
source /opt/seatable-compose/.env
echo -e "\n# onlyoffice" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
echo "ENABLE_ONLYOFFICE = True" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
echo "ONLYOFFICE_APIJS_URL = 'https://${SEATABLE_SERVER_HOSTNAME}:6233/web-apps/apps/api/documents/api.js'" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
echo "ONLYOFFICE_FILE_EXTENSION = ('doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'odt', 'fodt', 'odp', 'fodp', 'ods', 'fods', 'csv', 'ppsx', 'pps')" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
echo "ONLYOFFICE_JWT_SECRET = '${ONLYOFFICE_JWT_SECRET}'" >> /opt/seatable-server/seatable/conf/dtable_web_settings.py
```
You don't need to manually replace the variables `${SEATABLE_SERVER_HOSTNAME}` and `${ONLYOFFICE_JWT_SECRET}`. They will be automatically replaced as we have sourced the `.env` file.
#### Download onlyoffice and restart
One more step is necessary to download the OnlyOffice container and restart the SeaTable service.
```bash
cd /opt/seatable-compose
docker compose down
docker compose up -d
```
OnlyOffice takes some some minutes for the initial start. If you get an error message when clicking an office file in SeaTable, be patient and try again after one minute. Onlyoffice is ready, if a new browser window opens with your office document. Any user with access to this base can now open this document with OnlyOffice.
## Check if installation is complete
Try to open `https://SEATABLE_SERVER_HOSTNAME:6233/welcome`. You should see a welcome page like this.

If this does not happen, execute `docker compose logs onlyoffice -f` to get more details about the startup of OnlyOffice.
## Advanced: Custom settings
The following configuration options are only for OnlyOffice experts. You can create and mount a custom configuration file to [force some settings](https://helpcenter.onlyoffice.com/docs/installation/docs-developer-configuring.aspx).
Create a configuration file in `/opt/seatable-compose`:
```bash
nano onlyoffice-config.json
```
Copy the following code block into this file:
```json
{
"services": {
"CoAuthoring": {
"autoAssembly": {
"enable": true,
"interval": "5m"
}
}
},
"FileConverter": {
"converter": {
"downloadAttemptMaxCount": 3
}
}
}
```
Create `custom-onlyoffice.yml` to mount the config file into the container:
```yaml
services:
onlyoffice:
volumes:
- ./onlyoffice-config.json:/etc/onlyoffice/documentserver/local-production-linux.json
```
**Note:** Using a dedicated `.yml` file instead of modifying the default `onlyoffice.yml` file ensures that any modifications are preserved across version upgrades of SeaTable.
You can read our [guide](../../configuration/customizations.md) for detailed information on how this works.
Add `custom-onlyoffice.yml` to the `COMPOSE_FILE` variable and restart OnlyOffice to load the new configuration:
```bash
docker compose up -d
```
## Advanced: OnlyOffice on a separate host and URL
It is not that difficult to install OnlyOffice on a separate host to free the resources of the main server. This manual assumes that OnlyOffice will be accessible via a separate public URL.
### Install OnlyOffice
Start with the installation of docker and docker compose like it is described in the installation manual of SeaTable Server.
This is how your .env file should look like:
```bash
COMPOSE_FILE='caddy.yml,onlyoffice.yml'
COMPOSE_PATH_SEPARATOR=','
# onlyoffice url
SEATABLE_SERVER_HOSTNAME=
ONLYOFFICE_PORT=443
ONLYOFFICE_JWT_ENABLED=true
ONLYOFFICE_JWT_SECRET=
```
Now execute `docker-compose up -d` and on this server only caddy and OnlyOffice will be installed. Verify that OnlyOffice is reachable by opening your browser and open `https:///welcome/`.
### Configure SeaTable to use this new OnlyOffice host.
The next step is to tell SeaTable where it can access OnlyOffice. Update the settings in `dtable_web_settings.py` accordingly. Make sure to use the exact same shared secret and use the public URL of the OnlyOffice server.
You'll also have to configure the `ONLYOFFICE_HOSTNAME` variable inside your `.env` file.
This will cause the `Content-Security-Policy` header returned by Caddy to contain the correct values for the OnlyOffice hostname.
Remember to run `docker compose up -d` in order to apply the changes.
### Use Certificate store
If you are working with self signed or low trust certificates, there is an easy way to put your certificates to the onlyoffice container truststore. You can just mount your certificate to the onlyoffice container.
Create an additional `custom-onlyoffice.yml` file and add this file to the `COMPOSE_FILE` variable.
The file should contain the following contents:
```yaml
services:
onlyoffice:
volumes:
# mount certificates to onlyoffice container
- ./ca-certificates.crt:/var/www/onlyoffice/Data/certs/tls.crt:ro
```
---
## Monitoring
Source: https://admin.seatable.com/installation/components/gatus/
# Gatus
[Gatus](https://github.com/TwiN/gatus) provides your users with a real-time status page for your SeaTable Server and alerts you if any core components become unreachable. By default Gatus monitors the following components:
- SeaTable Login Page
- SeaTable API Gateway
- MariaDB
- Redis
- Certificate Expiration
- Python Pipeline
{style="border-radius:12px; padding:16px; background-color:#020817"}
## Installation
This guide explains how to install **Gatus** on your SeaTable server.
#### Change the .env file
As with other additional components, first add `gatus.yml` to the `COMPOSE_FILE` variable in your `.env` file.
Copy and paste (:material-content-copy:) the following command into your terminal:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,gatus.yml'/" /opt/seatable-compose/.env
```
#### Start Gatus
To start Gatus for the first time, run:
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
#### Verify the setup
Open `https:///status` or `https://:6220` in your browser to check if your new status page is accessible. This page will monitor your main components in real time. To reach this page, you must open/expose the port 6220 in your firewall.
## E-Mail notifications
Email notifications are preconfigured. You only need to provide the following environment variables in your `.env` file:
```bash
GATUS_EMAIL_USERNAME=
GATUS_EMAIL_PASSWORD=
GATUS_EMAIL_HOST=
GATUS_EMAIL_PORT=
GATUS_EMAIL_FROM=
GATUS_EMAIL_TO=
```
Each variable is self-explanatory.
## Additional Notifications and Advanced Configuration
Gatus uses two configuration files: `/opt/seatable-compose/gatus.yml` and `/opt/seatable-compose/config/gatus-config.yml`.
To ensure that your changes persist after updates, you should not modify the original versions of these files.
Instead, we recommend that you create an additional `custom-gatus.yml` file that contains a volume mount which mounts your own version of `gatus-config.yml` into the Gatus container.
Please read our [guide](../../configuration/customizations.md) on how this works before proceeding.
For all available configuration options, see the [Gatus GitHub repository](https://github.com/TwiN/gatus).
---
Source: https://admin.seatable.com/installation/components/dozzle/
# Dozzle
[Dozzle](https://dozzle.dev/) is a lightweight, open-source web-based log viewer for Docker containers. It provides real-time monitoring of container logs without storing data persistently, making it ideal for quick debugging in containerized environments like SeaTable. Key features include fuzzy and regex search, SQL-based log queries, split-screen views for multiple containers, live CPU/memory stats, and multi-user authentication.
A dedicated sidecar container (`seatable-logs` based on `sumologic/tailing-sidecar`) tails SeaTable log files from `/opt/seatable-server/seatable/logs` and redirects them to stdout, enabling seamless aggregation by **Dozzle** via the Docker socket.
In a SeaTable context, it simplifies troubleshooting by aggregating logs from all services in your Docker Compose stack via the shared Docker socket.
{style="border-radius:12px; padding:16px; background-color:#f5f5f5"}
Dozzle logs may expose sensitive information like passwords, API keys, base URLs or personal data. Restrict access to authorized users only and avoid public exposure.
## Installation
This guide explains how to install **Dozzle** on your SeaTable server.
### Change the .env file
As with other additional components, first add `dozzle.yml` to the `COMPOSE_FILE` variable in your `.env` file.
Copy and paste (:material-content-copy:) the following command into your terminal:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,dozzle.yml'/" /opt/seatable-compose/.env
```
### Create a dozzle admin login
Dozzle requires you to create login credentials. Use the command line tool `pwgen` to create a secure password for your *dozzle admin account*.
The following command will generate the necessary file at `/opt/dozzle/users.yaml`:
```bash
export DOZZLE_PASSWORD=`pwgen -c 40 1`
docker run -it --rm amir20/dozzle generate --name DozzleAdmin --email dozzleadmin@example.com --password ${DOZZLE_PASSWORD} dozzleadmin > /opt/dozzle/users.yaml
echo 'Now you can login to dozzle with `dozzleadmin` + `'${DOZZLE_PASSWORD}'`'
```
Alternatively, you can change the command and adapt it to your needs.
When setting passwords manually (without `pwgen`), do **not** use special characters such as `%`, `#`, `$`, `&`, `'`, `"` or similar. These may cause issues and can prevent that you can login to Dozzle.
Instead, choose a **long password** using uppercase, lowercase, and digits to ensure both compatibility and security.
### Start Dozzle
To start **Dozzle** for the first time, run:
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
## Next steps
After startup, **Dozzle** is accessible at `https://:6241`.
---
Source: https://admin.seatable.com/installation/components/uptime-kuma/
# Uptime Kuma
This guide shows how to activate Uptime Kuma on a one node seatable server.
## Installation
### Change the .env file
Add _uptime-kuma.yml_ to the COMPOSE_FILE variable.
```bash
nano /opt/seatable-compose/.env
```
Your COMPOSE_FILE variable should look something like this:
```bash
COMPOSE_FILE='seatable-docker-proxy.yml,seatable-server.yml,uptime-kuma.yml'
```
### Update the compose project
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
### Configure your Uptime Kuma
Your Uptime Kuma Container provides a Web UI to set up your Uptime Kuma Admin User under `https://:6230`.
## Things to monitor of your seatable server
Paths:
- https://deploy.seatable-demo.de/api2/ping/
- https://deploy.seatable-demo.de/dtable-server/ping/
- ...
- https://deploy.seatable-demo.de:6231/healthz (n8n)
- https://deploy.seatable-demo.de:6232/ (collabora online)
- https://deploy.seatable-demo.de:6233/welcome/ (onlyoffice)
- ...
## Screenshots
will be added shortly.
---
Source: https://admin.seatable.com/installation/components/zabbix/
# Zabbix Monitoring
Install Zabbix Agent and Zabbix Server on the same host to monitor system status.
## Get the Zabbix Server:
After installation, you can get access to the zabbix server webinterface
- Login to Zabbix Server Browser: `https://:6235`
Initial Login with: Admin/zabbix
## After login:
Go to `Monitoring > Hosts`. Change Host Configuration of **Zabbix server** :
From: IP 127.0.0.1
To: DNS zabbix-agent
After some seconds the monitoring will run and deliver data.
---
Source: https://admin.seatable.com/installation/components/releem/
# Releem
**Releem** is a MySQL performance monitoring and tuning tool designed to optimize your MariaDB database. It operates alongside your database, collecting performance data and providing recommended configuration improvements. While Releem offers automated insights, experienced database professionals may prefer manual tuning for deeper control.

## Register for a releem account
- Visit the [Releem website](https://releem.com/) and sign up for a new account.
- After registration, obtain your **RELEEM_API_KEY**.
## Create a dedicated database user
Releem requires its own user in your MariaDB instance. Log in to your MariaDB server and execute the following commands, replacing `[RELEEM_DB_USER_PASSWORD]` with a secure password:
```sql
CREATE USER 'releem'@'%' identified by '[RELEEM_DB_USER_PASSWORD]';
GRANT PROCESS, REPLICATION CLIENT, SHOW VIEW ON *.* TO 'releem'@'%';
GRANT SELECT ON performance_schema.events_statements_summary_by_digest TO 'releem'@'%';
GRANT SELECT ON performance_schema.table_io_waits_summary_by_index_usage TO 'releem'@'%';
```
## Configure Releem in your environment
Add `releem.yml` to the `COMPOSE_FILE` variable in your `.env` file and set the following environment variables:
- **RELEEM_HOSTNAME**: A unique identifier for your server (useful if monitoring multiple systems).
- **RELEEM_DB_USER_PASSWORD**: The password you set above.
- **RELEEM_API_KEY**: Your API key from Releem.
## Data collection and optimization
After starting the Releem agent, it will begin collecting performance metrics from your MariaDB database. Within 24 hours, Releem will provide optimized configuration recommendations based on your database workload.
## Apply optimized MariaDB settings
1. **Create a Custom Configuration File**
Create a file named `99-mariadb-custom.cnf` with your optimized settings that Releem recommended to you.
**This is just an example:**
```ini
[mariadb]
query_cache_limit = 1M
query_cache_size = 128M
expire_logs_days = 10
innodb_buffer_pool_size = 1946157056
```
2. **Mount the Configuration File in Your Docker Compose Setup**
Add the following volume to your `docker-compose.yml` for the MariaDB service:
```yaml
---
services:
mariadb:
...
volumes:
- "/opt/mariadb:/var/lib/mysql"
- "./99-mariadb-custom.cnf:/etc/mysql/conf.d/99-mariadb-custom.cnf"
```
3. **Restart MariaDB**
Restart your MariaDB container to apply the new settings.
After the restart, your database will use the new configuration. Releem will continue to monitor and suggest further optimizations as needed.
---
## Single-Node Deployment
Source: https://admin.seatable.com/installation/components/restic/
# Restic Backup
Running your own server always requires a reliable backup to secure your data. With this backup container, obtaining a daily backup is easy. We chose the backup software Restic for its numerous advantages:
- **Target:** Restic supports multiple backup targets, including S3, Backblaze, BorgBase, Dropbox, and Google Drive.
- **Speed:** Backup your data at lightning speed.
- **Encryption:** Your data is securely encrypted. Without the encryption key, it remains inaccessible.
- **Deduplication:** Duplicate files or file fragments are saved only once, reducing the amount of data transmitted.
- **Snapshots:** Forget about regular full backups; only the changes since the last backup need to be saved.
- **Reliability:** With 24k stars on GitHub and nearly a decade of development, restic is exceptionally robust.

## Installation
This article explains how to implement a restic backup for your SeaTable server.
#### Change the .env file
To install the restic backup container, include `restic.yml` in the `COMPOSE_FILE` variable within your `.env` file. This instructs Docker to download the required images.
Simply copy and paste (:material-content-copy:) the following code into your command line:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,restic.yml'/" /opt/seatable-compose/.env
```
#### Configure your backup
Every backup is encrypted with a password. Please make sure that you store this password at a safe place, otherwise your backup will be worthless if you might need it.
```bash
pw=$(pwgen -s 40 1) && echo "Generated restic password: ${pw}"
```
The generated restic password needs to be added to your `.env` file. Copy and paste the following command:
```bash
echo -e "\n# restic-backup" >> /opt/seatable-compose/.env
echo "RESTIC_PASSWORD=${pw}" >> /opt/seatable-compose/.env
```
This configuration will create daily snapshots including database dumps at your host system at `/opt/restic/local`. This is a good start, but of course we recommend that you store your backup remotely.
??? success "Secure offsite backup with BorgBase"
For small SeaTable servers, we could recommend the service BorgBase. They offer up to 10GB of Backup storage for free and the setup can be done in one minute.
1. Register at .
2. Create a new repo, choose any name and set the **Repo Format: Restic**.
3. Save the provided **repository url** and use it as `RESTIC_REPOSITORY`.

This is all that is necessary to create a secure offsite backup.
#### Other backup targets
To use another backup target then the local path `/opt/restic/local` you have to provide the additional environment variable `RESTIC_REPOSITORY`. Some backends require additional environment variables for authentication.
Here are some examples. For more details, refer to the [official restic documentation](https://restic.readthedocs.io/en/stable/).
=== "REST Server"
```bash
RESTIC_REPOSITORY='rest:https://user:pass@host/'
```
=== "Amazon S3"
```bash
RESTIC_REPOSITORY='s3:s3.amazonaws.com/bucket_name'
AWS_ACCESS_KEY_ID='...'
AWS_SECRET_ACCESS_KEY='...'
```
=== "Backblaze B2"
```bash
RESTIC_REPOSITORY='s3:s3.amazonaws.com/bucket_name'
B2_ACCOUNT_ID='...'
B2_ACCOUNT_KEY='...'
```
=== "rclone"
rclone is already installed in the backup container and expects the configuration file at `/root/.config/rclone/rclone.conf`. Generate your rclone.conf at the host and mount it to the container at this location. Then you can use restic with rclone as described in the manual.
```bash
volumes:
...
- /opt/restic/rclone.conf:/root/.config/rclone/rclone.conf:ro
```
```bash
RESTIC_REPOSITORY='rclone:xxx:yyy'
```
## Start the backup
Now it is time to load the container and start the backup for the first time.
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
Afterwards check the logs for more details.
```bash
docker logs restic-backup
```
The output might look like this:
```console
[2024-05-17 16:16] Starting the restic backup container ...
[2024-05-17 16:16] Restic repository '/local' does not exists.
Running restic init.
created restic repository 7982e3a700 at /local
Please note that knowledge of your password is required to access the repository
Losing your password means that your data is irrecoverably lost.
[2024-05-17 16:16] Setup backup cron job with cron expr. BACKUP_CRON: 20 2 * * *
[2024-05-17 16:16] Setup check cron job with cron expr. CHECK_CRON: 40 3 * * 6
[2024-05-17 16:16] Container started successful.
The restic repository is initialized, cron daemon runs...
Ready for backup!
```
:material-party-popper: **Perfect!** Your backup was initialized and will run every day at 2.20am.
More information about the usage of the restic backup container can be found at the github repository [:simple-github: restic-backup-docker](https://github.com/seatable/restic-backup-docker).
---
Source: https://admin.seatable.com/installation/components/ofelia/
# Ofelia
[Ofelia](https://github.com/mcuadros/ofelia) is a job scheduler for Docker that allows you to run scheduled commands inside Docker containers.
The commands and their respective schedules are specified through Docker labels.
## Installation
### Update the .env File
To install Ofelia, add `ofelia.yml` to the `COMPOSE_FILE` variable in your `.env` file. This tells Docker to download the required Ofelia image.
Simply copy and paste (:material-content-copy:) the following code into your command line to update your `.env` file:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,ofelia.yml'/" /opt/seatable-compose/.env
```
### Start Ofelia
Start Ofelia for the first time by running the following commands:
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
### Logs
You can use `docker logs -f ofelia` to view Ofelia's logs. By default, Ofelia forwards the output of all scheduled commands to its own `stdout` file descriptor.
## Configuration
By default, `ofelia.yml` adds labels to the `seatable-server` service. These labels schedule three maintenance commands that run inside the `seatable-server` container:
| Slug | Description | Schedule |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- | --------- |
| `clean-tmp` | Removes any files older than 3 days from the `/tmp` directory inside the container to the system from running out of disk space | `@weekly` |
| `gc` | Runs the [garbage collection](../../maintenance/storage-cleanup.md) process to clean up unused `block` and `fs` objects | `@weekly` |
| `seaf-fsck` | Runs the [`seaf-fsck`](../../maintenance/filesystem-check.md) script to check the integrity of all Seafile libraries | `@weekly` |
You are free to modify the schedule of these commands and/or add your own commands via additional labels on the `seatable-server` container.
Please refer to [Ofelia's docs](https://github.com/mcuadros/ofelia/blob/master/README.md#configuration) for more details regarding the configuration format.
Since Ofelia does not yet support the automatic reloading of label configuration, any changes to the Docker labels require a manual restart of Ofelia.
You can achieve this by running the following command:
```bash
# --force-recreate ensures that Ofelia is restarted
docker compose up -d ofelia --force-recreate
```
---
Source: https://admin.seatable.com/installation/components/clamav/
# Deploy ClamAV with SeaTable
SeaTable supports antivirus scanning using ClamAV. It automatically scans newly uploaded or updated assets (such as images and files) for viruses.
## Installation
### Update the .env File
To install ClamAV, add `clamav.yml` to the `COMPOSE_FILE` variable in your `.env` file. This tells Docker to download and configure the required ClamAV image.
Simply copy and paste (:material-content-copy:) the following code into your command line to update your `.env` file:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,clamav.yml'/" /opt/seatable-compose/.env
```
### Configure dtable-events
Depending on your SeaTable version, this is done either through a config file or through environment variables:
=== "SeaTable <= v6.1"
Add the following configuration to the `dtable-events.conf` file to enable virus scanning:
```ini
[VIRUS SCAN]
enabled = true
scan_command = clamdscan
scan_interval = 60
virus_code = 1
nonvirus_code = 0
```
=== "SeaTable v6.2+"
You'll have to configure a few additional environment variables.
Please read our [guide](../../configuration/customizations.md) that explains how to configure these additional environment variables before proceeding.
```ini
VIRUS_SCAN_ENABLED=true
VIRUS_SCAN_SCAN_COMMAND=clamdscan
VIRUS_SCAN_SCAN_INTERVAL=60
VIRUS_SCAN_VIRUS_CODE=1
VIRUS_SCAN_NONVIRUS_CODE=0
```
### Start ClamAV
Start ClamAV for the first time by running:
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
Once started, you should see an entry like this in your `dtable-events.log`:
```log
[INFO] virus_scanner.py[line:21] Start virus scanner, interval = 3600 sec
```
ClamAV will now continuously scan images and files attached to your bases for viruses.
## Usage
After enabling ClamAV, a new section will appear in the admin area where you can view detected viruses. For each finding, you’ll see:
- The base where the infected file is located.
- The file name.
- The current status of the detection.
You can choose to either ignore the finding or delete the infected asset.

## Advanced Topics
### Additional Configuration Options
ClamAV offers advanced configuration options in `dtable-events.conf`/through environment variables, such as:
- **Scan interval**: Adjust how often scans are performed.
- **File size limit**: Set a maximum size for scanned files.
- **Ignored file extensions**: Specify file types to exclude from scanning.
- **Thread count**: Define how many threads are used for scanning.
For more details, refer to the [dtable-events configuration documentation](../../configuration/components/dtable-events.md).
## Updating Virus Signature Files
The ClamAV Docker container uses Freshclam to update its virus signature database automatically every three hours. While this keeps ClamAV up-to-date, its detection capabilities may not be as robust as those of other paid antivirus solutions.
## E-Mail notification
Email notifications for virus detection will be available in a future update.
---
Source: https://admin.seatable.com/installation/faq/
## Troubleshooting SeaTable Server
??? question "SeaTable doesn't start / Webinterface is not reachable"
First let's try to find out, where the problem is. If you try to access your SeaTable Server goes like this:
**Browser** -> **Domain/DNS** -> **Caddy** -> **Nginx** -> **SeaTable Container** -> **SeaTable Server**
Check the following solutions to determine what is not running.
??? question "Verify that SeaTable Server is running"
Execute `docker logs seatable-server`. This should result in:
```text
2024-02-04 12:59:17 Start server
SeaTable started
2024-02-04 12:59:21 For more startup information, please check the /opt/seatable/logs/init.log
2024-02-04 12:59:21 This is an idle script (infinite loop) to keep container running.
```
---
Another check might be:
```bash
docker exec -it seatable-server curl http://127.0.0.1:8000/server-info/
```
This should return:
```json
{"version":"6.1.3","edition":"enterprise edition"}
```
If you don't see this, SeaTable Service is definitely not running. Try to [restart the service](../maintenance/restart-seatable.md) and check the logs for more details.
Here are the two commands for more logs
- `cd /opt/seatable-compose && docker compose logs -f`
- `tail -f /opt/seatable-server/seatable/logs/*.log`
Probably you have a wrong configuration value in `dtable_web_settings.py`.
??? question "Verify that SeaTable Container is healthy"
Execute `docker ps`. This should be the result:
```text
CONTAINER ID IMAGE STATUS NAMES
0411d977eb25 seatable/seatable-enterprise:6.1.3 Up 3 days (healthy) seatable-server
```
If the container is not (healthy), you can be sure, that something is wrong with the container.
??? question "Check dtable-server"
You can check the status of `dtable-server` by executing the following curl request:
```bash
curl https://$SEATABLE_SERVER_HOSTNAME/dtable-server/ping/
```
If `dtable-server` does not reply, it might be stuck in a reboot loop.
This can happen if too many large bases are loaded at once or too many pending operations need to be replayed.
In this case, `monitor.log` contains log entries such as `[WARNING] Ping error, kill dtable-server`.
As a workaround, you can increase the timeout for the healthcheck request to give `dtable-server` more time to load bases and apply pending operations.
This can be achieved by increasing the value of the `DTABLE_SERVER_PING_TIMEOUT` environment variable (the default is `20`).
**Note:** This variable is not part of the default `seatable-server.yml` file, so you need to include an additional `.yml` file in order to configure this variable.
??? question "Check nginx"
There might be a misconfiguration of `nginx.conf`. nginx provides a configuration checker.
```bash
docker exec -it seatable-server nginx -t
```
It should look like:
```text
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
If not, check the nginx configuration file at `/opt/seatable-server/seatable/conf/nginx.conf`.
??? question "Check Caddy"
```bash
docker logs caddy
```
more info will follow.
??? question "Check dtable-web"
Run the [`check-dtable-web.sh` script](../maintenance/helper-scripts.md#check-dtable-websh) in order to troubleshoot `dtable-web`.
??? question "Domain/DNS"
execute `curl https://` or `ping ` to get more details.
??? question "Other typical problems"
- License expired or not provided
- PLUGIN_REPO_ID wrong in dtable_web_settings.py
- spaces in COMPOSE_FILE variable in `.env` file.
## FAQs
??? question "If, for whatever reason, the installation fails, how do I to start from a clean slate again?"
Stop all containers, remove the directories caddy, mariadb, seatable-compose, and seatable-server in `/opt` and start again.
To stop all containers, change to `/opt/seatable-compose` and run `docker compose down`.
??? question "I want to run my SeaTable Server instance on my local machine? Can I do that?"
You can, but it is only recommended for testing purposes. Follow the [instructions for the single-node deployment](./basic-setup.md) and simply set SEATABLE_SERVER_HOSTNAME and SEATABLE_SERVER_PROTOCOL to `127.0.0.1` and 'http', respectively, in the `.env` file. To access your local SeaTable Server instance, enter http://127.0.0.1 in your browser.
If you want to enable https, consult section [Custom Certificates](./advanced/custom-certificates.md) for details.
??? question "I want to use my own reverse proxy / my custom certificate, how do I do that?"
You can opt out of using Caddy and use another webserver of your choice. In this case, remove `caddy.yml` from the COMPOSE_FILE variable in the `.env` file and follow the instructions in section [Custom Reverse Proxy](./advanced/custom-proxy.md).
??? question "SeaTable terminates with `/shared/seatable/seatable-license.txt: Is a directory`"
In the `seatable-server.yml` file, the SeaTable license file is mounted into the container:
```yaml
- type: bind
source: "./seatable-license.txt"
target: "/shared/seatable/seatable-license.txt"
read_only: ${SEATABLE_LICENSE_FORCE_READ_ONLY:-false}
```
This error occurs when SeaTable is started before the `seatable-license.txt` file exists in the `/opt/seatable-compose` directory. In this case, Docker automatically creates a directory named `seatable-license.txt` instead of a file. Even after adding the license file later, SeaTable cannot start because the directory remains in place.
**Solution**
Stop the SeaTable container, remove the directory that Docker created by mistake: and restart SeaTable.
```bash
docker stop seatable-server
rm -r /opt/seatable-server/seatable/seatable-license.txt
docker start seatable-server
```
Ensure that the license file `seatable-license.txt` is present in `/opt/seatable-compose` before starting SeaTable again.
??? question "How can I reload dtable-web/Gunicorn without restarting the container/all container processes?"
You can run the following command **inside** the `seatable-server` container to restart all Gunicorn workers:
```bash
kill -HUP $(cat /var/run/dtable-web.pid)
```
This sends a `SIGHUP` signal to the Gunicorn master process, whose PID is stored inside the file `/var/run/dtable-web.pid`.
This allows you to apply changes to `dtable_web_settings.py` without causing downtime or aborting active WebSocket connections.
**Note:** In previous versions of SeaTable, the PID file was located at `/opt/seatable/pids/dtable-web.pid`.
---
## Webserver
Source: https://admin.seatable.com/installation/advanced/ipv6-support/
# Activate IPv6 Support for SeaTable
SeaTable supports IPv6 in general. There is no special activation required.
## Docker and IPv6
### Problem
There is one area that requires additional attention. Docker, by default, does not assign IPv6 addresses to its containers; instead, containers receive only IPv4 addresses.
Requests arriving via an IPv6 connection still reach SeaTable. However, a problem arises for services like nginx or SeaTable that log the source IP address. Every incoming IPv6 request is logged with the Docker network gateway IP address (e.g., `172.18.0.1`), not the client’s actual IPv6 address. In the following screenshot, you can see that *Thierry* connected from an IPv6 address.

You can confirm this by running `docker inspect seatable-server`:
```json
[
{
...
"Networks": {
"frontend-net": {
...
"Gateway": "172.18.0.1",
"IPAddress": "172.18.0.5",
"IPv6Gateway": "",
"GlobalIPv6Address": "",
...
}
}
}
]
```
While this does not cause immediate service disruptions, it presents some challenges:
- Incorrect client IPs are logged.
- Rate limiting or other IP-based limits may behave incorrectly.
---
### Solution
The solution is straightforward. Add the following parameter to your Docker network configuration (for example, in caddy.yml):
```yaml
networks:
frontend-net:
name: frontend-net
enable_ipv6: ${ENABLE_IPV6:-true}
```
This enables IPv6 addressing for the container and ensures accurate logging of client IP addresses. **Starting with SeaTable version 6.0**, this feature is enabled by default.
---
### Setups without IPv6
If IPv6 is completely disabled, Docker may fail to start containers with errors such as:
- `cannot read IPv6 setup`
- `cannot assign requested address`
- `failed to start container ... error="driver failed programming external connectivity`
- `error response from daemon: attaching to network failed`
In this case, set `ENABLE_IPV6=false` in your `.env` file to disable IPv6 support in Docker, allowing containers to start successfully.
---
Source: https://admin.seatable.com/installation/advanced/custom-proxy/
# Replace caddy with another proxy
The Single-Node Installation describes an installation of a SeaTable server with the webserver caddy. We decided to use Caddy because it simplifies the handling of let's encrypt certificates.
If you create a DNS entry and point it to your server, caddy will do everything else for you. Also we configured caddy with state of the art security configurations.
## Custom proxy with SeaTable Server
But of course there might be reasons when you want to replace caddy with another proxy like ha-proxy, traefik, nginx, apache etc. The logic of replacing might be simple.
You can use any proxy as long as your forward all traffic to the SeaTable Server. Part of the SeaTable Server container is a nginx web proxy, which routes the traffic by URL. **This port 80 is not exposed therefore your proxy has to be in the same docker network like SeaTable Server**.

## How to configure
Remove `caddy.yml` from COMPOSE_FILE from .env file. Restart all docker containers. Forward all traffic to the SeaTable Container via port 80.
Please be aware that SeaTable does not expose port 80 to the outside. Therefore your proxy has to be in the same docker network. Otherwise you have to expose port 80 of SeaTable Server.
## Custom proxy with additional components
For the additional components you can choose between two different options. You can access the services either via separate port or (sub)domain.
### Option 1: use ports to access the services
The additional components run on separate ports. n8n uses the port 6231. If you only have one public domain available, you can forward the required port to the internal network and access the service. This does not require any further configuration.

### Option 2: other domains to access the services
In this case, you use another (sub)domain to access the service. You create a proxy rule to route the traffic to the service with its internal port. Usually this requires that you also change the configuration of the service to be accessible via this additional domain.

## Proxy outside of the docker network
To use a proxy outside of your Docker network, you’ll need to expose port 80 on your SeaTable server and route all traffic through it. Alternatively, you can expose a different port and forward it to the internal port 80 on Nginx.
Because network configurations vary widely, it’s difficult to provide specific instructions for every setup. This approach requires familiarity with networking and routing concepts.
---
Source: https://admin.seatable.com/installation/advanced/webserver-dns-challenge/
# Using Let's Encrypt with DNS Challenge (caddy-dns) Instead of HTTP Ports 80/443
By default, SeaTable uses Caddy with the HTTP-01 challenge method to automatically request and renew a Let's Encrypt certificate. This approach requires that ports **80** and **443** are publicly reachable so that Let's Encrypt can validate domain ownership.
In environments where these ports cannot or should not be exposed (e.g. internal installations, restrictive firewalls, or isolated networks), you can alternatively use the **DNS-01 challenge** via the **caddy-dns plugins**.
## Advantages and Requirements of DNS Challenge
When using the DNS challenge:
- No inbound HTTP/HTTPS access from the internet is required.
- The system does not need to be publicly reachable.
- Certificate validation happens via DNS TXT records.
This setup requires building a custom Docker image that includes:
- the appropriate DNS provider plugin
- the `caddy-docker-proxy` plugin
Therefore, this configuration is intended for advanced administrators who are familiar with managing DNS zones and understand DNS propagation behavior.
**caddy-dns** supports many common DNS providers (e.g. Hetzner, Cloudflare, Route53 and others). A full list is available in the official repository:
[caddy-dns](https://github.com/caddy-dns)
Make sure your DNS provider is supported. Otherwise, this setup will not work.
Depending on your provider, you may need:
- An API token
- API key and secret
- A dedicated DNS API user
- Appropriate zone permissions
## Step 1: Replace the Default Caddy Configuration
Instead of using the default `caddy.yml`, create a new YAML file that builds a custom Caddy container.
Your custom Caddy must include two plugins:
- `lucaslorentz/caddy-docker-proxy`
- `caddy-dns/your-dns-provider`
You can find the correct plugin name for your DNS provider at: [https://github.com/caddy-dns](https://github.com/caddy-dns)
Even though ports 80 and 443 are still mapped internally, they do **not** need to be publicly reachable for DNS-01 validation.
Below is an example using the **Hetzner DNS plugin**:
```yaml
---
services:
caddy:
build:
dockerfile_inline: |
ARG CADDY_VERSION=2.10.2
FROM caddy:$${CADDY_VERSION}-builder AS builder
RUN xcaddy build \
--with github.com/lucaslorentz/caddy-docker-proxy/v2 \
--with github.com/caddy-dns/hetzner/v2
FROM caddy:$${CADDY_VERSION}-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
CMD ["caddy", "docker-proxy"]
container_name: caddy
restart: unless-stopped
environment:
- CADDY_INGRESS_NETWORKS=frontend-net
networks:
- frontend-net
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./volumes/caddy:/data
networks:
frontend-net:
name: frontend-net
```
## Step 2: Configure TLS for SeaTable
Next, configure Caddy to use the DNS challenge by adding the `caddy.tls` labels to your SeaTable service definition.
The exact configuration depends on your DNS provider. In most cases, the API token must have permission to manage DNS records for the corresponding zone.
=== "Hetzner"
```text
caddy_0.tls.dns: "hetzner ${HETZNER_DNS_TOKEN:?Variable is not set or empty}"
caddy_0.tls.propagation_delay: 30s
```
=== "Cloudflare"
```text
caddy_0.tls.dns: "cloudflare {CLOUDFLARE_API_TOKEN:?Variable is not set or empty}"
```
If you have deployed additional components such as [Collabora](../components/collabora.md) or [n8n](../components/n8n.md) that are directly exposed by Caddy
and they use the same hostname as your SeaTable installation, you need to also add the `caddy.tls.dns` label to these services.
Otherwise Caddy will log the following error:
```
Removing invalid block: hostname appears in more than one automation policy, making certificate management ambiguous
```
## Step 3: Create and Configure the DNS API Token
Log in to your DNS provider’s account and generate an API token with permission to manage DNS records for the required zone.
The required permissions for each provider are typically documented in the corresponding plugin directory at: https://github.com/caddy-dns.
Add the generated token to your `.env` file, for example:
=== "Hetzner"
```ini
# Caddy DNS-01 challenge
HETZNER_DNS_TOKEN=your_token_here
```
=== "Cloudflare"
```ini
# Caddy DNS-01 challenge
CLOUDFLARE_API_TOKEN=your_token_here
```
After restarting the Caddy container, Caddy will automatically:
1. Request or renew the certificate from Let's Encrypt
2. Create the required `_acme-challenge` TXT record via the DNS API
3. Wait for DNS propagation
4. Complete validation and remove the temporary record
No public inbound access to ports 80 or 443 is required for this process.
---
Source: https://admin.seatable.com/installation/advanced/custom-certificates/
# Custom root certificates
By default, Seatable uses Let's Encrypt to generate valid certificates for public access. However, Caddy also provides an easy way to use custom certificates. This section assumes that you intend to use a **valid (standard or wildcard) certificate issued by a widely trusted certificate authority**.
Self-signed certificates should only be used for testing purposes. Even if your clients or browsers trust the certificate, Docker containers do not trust each other by default.
For SeaTable Server and the Python Pipeline (scheduler and starter), the trust can be established by adding the certificate to their truststore (see below). The `python-runner` is started on demand by the `python-starter` and requires a separate setup (see [Custom CA for the python-runner](#custom-ca-for-the-python-runner)).
To avoid these issues entirely, use a valid (standard or wildcard) certificate issued by a recognized certificate authority.
## Make certificates available to caddy
With the caddy.yml a default volume-mount is created: `/opt/caddy:/data/caddy`
By convention you should provide your certificate & key files in the container host filesystem under `/opt/caddy/certs/` to make it available to caddy.
In the article, we assume that your certificates were saved as `cert.pem` and `key.pem`.
```bash
/opt/caddy/certs/
├── cert.pem
├── key.pem
```
With this command, you can generate your own custom certificates. Please be aware that custom certificates can not be used for ip-addresses. Remember to replace `${HOSTNAME}` with the actual hostname.
```bash
cd /opt/caddy/certs
openssl req -x509 -nodes -days 365 -addext "subjectAltName = DNS:${HOSTNAME}" -newkey rsa:2048 -keyout ./key.pem -out ./cert.pem
```
## Configure SeaTable Container to use custom certificates
The caddy docker proxy container from [lucaslorentz](https://github.com/lucaslorentz/caddy-docker-proxy) supports dynamic configuration with labels.
The provided `seatable-server.yml` file **should not be modified** to ensure that version upgrades stay seamless.
Instead, any customizations should be placed inside a dedicated `custom-seatable-server.yml` file.
Please read our guide that explains how to [customize the configuration](../../configuration/customizations.md) of your SeaTable instance before proceeding.
This `custom-seatable-server.yml` file needs to contain overrides that advise Caddy to use your custom certificates.
This is achieved through the `caddy.tls` label:
```yaml
# configuration of custom-seatable-server.yml
services:
seatable-server:
labels:
caddy: ${SEATABLE_SERVER_HOSTNAME}
caddy.tls: "/data/caddy/certs/cert.pem /data/caddy/certs/key.pem"
```
If you're using a non-public url like "my-custom-setup.local", you have to make sure, that the docker container can resolve this DNS query. If you don't run your own DNS servers, you have to add `extra_hosts` to your `.yml` file.
## Add certificates to your truststore
SeaTable Server and the Python Pipeline (Scheduler and Starter) execute the command `update-ca-certificates` at every start. This adds all certificates from `/usr/local/share/ca-certificates/` to the system trust store at `/etc/ssl/certs/ca-certificates.crt`.
This is relevant in two scenarios:
- **Self-signed or custom SeaTable certificates**: If SeaTable itself uses a self-signed or custom certificate, internal services need to trust it.
- **External services with custom CAs**: If SeaTable connects to external services that use certificates from a non-standard CA (e.g. a corporate SAML/SSO identity provider, LDAP server, or S3 storage), you need to add the corresponding root CA certificate to the trust store.
To add a certificate, mount the `.crt` file into the container via your `custom-seatable-server.yml`. This works for seatable-server, python-scheduler, and python-starter.
```yaml
services:
seatable-server:
volumes:
- "/opt/caddy/certs/cert.pem:/usr/local/share/ca-certificates/cert.crt"
```
You can mount multiple certificates by adding additional volume mounts. Every `.crt` file in `/usr/local/share/ca-certificates/` will be included in the trust store at startup.
Make sure that `REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt` is set in your environment variables. This tells all Python libraries (requests, pysaml2, etc.) to use the system trust store instead of their own bundled certificates. This variable is included by default since version 5.0 in the [seatable-server.yml](https://github.com/seatable/seatable-release/blob/main/compose/seatable-server.yml).
## Custom CA for the python-runner
The truststore setup described above covers the long-running `python-scheduler` and `python-starter` containers, but **not** the `python-runner`. The runner is an ephemeral container that the starter launches via `docker run` for every script execution. It is based on Alpine, runs as a non-root user, never executes `update-ca-certificates`, and has no certificate mounted into it. As a result, scripts that call `base.auth()` (or any other HTTPS endpoint with your custom CA) will fail with an SSL error — even though `print("hello world")` works fine.
To fix this, you need to do two things at the same time, both via [`PYTHON_RUNNER_OTHER_OPTIONS`](python-pipeline-configuration.md#mounting-additional-directories):
1. Mount the trusted CA bundle from the host into the runner.
2. Set `REQUESTS_CA_BUNDLE` inside the runner so that Python's `requests` library uses it (without this, `requests` falls back to the `certifi` bundle and ignores `/etc/ssl/certs/`).
### Build a merged CA bundle on the host
If you only mount your own certificate, the runner will no longer trust any public CAs, which can break scripts that call third-party APIs. The cleanest solution is to merge the host's public CA bundle with your custom certificate:
```bash
cat /etc/ssl/certs/ca-certificates.crt /opt/caddy/certs/cert.pem \
> /opt/seatable-compose/runner-ca-bundle.crt
```
The bundle is placed next to your compose files and `.env` so that it is co-located with the configuration that references it. Repeat this step whenever your custom certificate is renewed.
### Configure the python-starter
Add the following to your `custom-python-pipeline.yml` (create it if it does not exist) and reference the file in the `COMPOSE_FILE` variable of your `.env`:
```yaml
services:
python-starter:
environment:
- PYTHON_RUNNER_OTHER_OPTIONS=["--volume=/opt/seatable-compose/runner-ca-bundle.crt:/etc/ssl/certs/runner-ca-bundle.crt:ro","--env=REQUESTS_CA_BUNDLE=/etc/ssl/certs/runner-ca-bundle.crt"]
```
The value must be a valid Python list literal (parsed via `ast.literal_eval`). Each item is appended verbatim to the `docker run` command, so environment variables must use the `--env=KEY=VALUE` form — a bare `KEY=VALUE` would be interpreted as a positional argument and break the container start. Do not wrap the list in additional quotes.
Restart the `python-starter` with `docker compose up -d` afterwards. To verify, set `PYTHON_STARTER_LOG_LEVEL=DEBUG` and check `docker compose logs -f python-starter` — the full `docker run` command should now include both the volume mount and the `REQUESTS_CA_BUNDLE` environment variable.
## Self-signed certificates generated by Caddy
Even if it is not recommended, it is possible to ask Caddy to use auto generated self-signed certificates.
This can be achieved by adding the following lines to your `custom-seatable-server.yml`:
```yaml
# configuration of custom-seatable-server.yml
services:
seatable-server:
labels:
caddy: ${SEATABLE_SERVER_HOSTNAME}
caddy.tls: "internal"
```
## Problems with local IP
The current setup does not allow that you add a local IP address as `SEATABLE_SERVER_HOSTNAME` in your .env file. There are two alternatives that we recommend to use:
#### use local address
Instead of the IP address you should use an address like `seatable.local`. This requires that you either use a self-signed certificate or a custom root certificate.
#### use nip.io
There is a free service which allows mapping any IP Address to a hostname using the following formats:
- 10.0.0.1.nip.io maps to 10.0.0.1
- 192-168-1-250.nip.io maps to 192.168.1.250
- 0a000803.nip.io maps to 10.0.8.3
So if you want to use the local address like `192.168.17.20`, you should use `192.168.17.20.nip.io` as `SEATABLE_SERVER_HOSTNAME`.
## Limitations
Currently it is not possible to generate PDF-Files with the Page Design Plugin if you're running SeaTable with your self-signed certificate.
The workaround is to use `Print` inside the Page Design Plugin and then use a local PDF-Printer to generate the PDF.
---
Source: https://admin.seatable.com/installation/advanced/http-only/
# Force http only for your SeaTable Server
## Force http during installation
It is not recommended to run SeaTable without https. Still it is possible. During the installation it is sufficient to set the .env variable `SEATABLE_SERVER_PROTOCOL` with the value `http` and all configuration files and caddy will be set up correctly.
## Switching after the installation
If you want to force http after the initial setup, you also have to adapt these configuration files and replace all https:// values with http://:
- dtable_web_settings.py
- ccnet.conf
- nginx.conf
Especially the change of the nginx file is not trivial, if you don't have any experience with nginx.
---
Source: https://admin.seatable.com/installation/advanced/additional-subdomains/
# Additional Subdomain
By default SeaTable and all additional components use one single public available domain. This manual explains what to do if you want to make an additional component like n8n available via (sub)domain instead of a port. This article describes the necessary change to the existing caddy container. If you want to use a complete different proxy, please refer the the article ...
## Typical configuration
Look at `n8n.yml` to get an understanding of how caddy is configured to make n8n accessable via port 6231.
```yaml
services:
caddy:
ports:
- ${N8N_PORT:-6231}:${N8N_PORT:-6231} # <-- enhances caddy.yml
n8n-postgres:
...
n8n:
...
```
In the n8n.yml we add an additional port to the caddy container by adding an additional port. Imagine you use seatable.example.com to access SeaTable, then port 443 is routed to SeaTable and port 6231 is routed to the n8n container.
## New configuration to use a custom domain
The following example assumes that you want to access n8n not anymore via the port 6231 but with the URL `n8n.example.com`.
1. Create `custom-n8n.yml` to extend the default definition of the `n8n` service.
2. Insert the following block into `custom-n8n.yml`:
```yaml
services:
n8n:
labels:
caddy: n8n.example.com
caddy.reverse_proxy: "{{upstreams 5678}}"
```
3. Add `custom-n8n.yml` to the `COMPOSE_FILE` variable inside your `.env` file.
This configures Caddy to proxy all requests for `n8n.example.com` to port 5678 of the `n8n` service.
Apply the changes by running the following command inside `/opt/seatable-compose`:
```bash
docker compose up -d
```
---
Source: https://admin.seatable.com/installation/advanced/air-gap-installation/
# Air gap installation
Air gap installation means that your SeaTable server has no connection to the internet and runs air gapped on the local network. This is feasible for high-security environments but it should be obvious that such a setup requires additional configurations and is not an easy task.
This article is a summary of the topics that should be considered.
## Problems that arise with air gap:
- Certificate management (HTTPS/TLS) is complicated.
- A separate container registry is necessary.
- A local APT repository is necessary.
- Plugins have to be installed manually.
Let's go into the details.
### Certificate Management
The easiest solution would be to just use HTTP for all communication but this contradicts the idea of increased security of an air gapped setup. Therefore it is necessary that you use a **globally trusted wildcard certificate**. This is quite easy to obtain but will cost some money. This manual explains how to use such a custom root certificate.
### Separate container registry
Usually SeaTable Server and the other containers are downloaded from [Docker Hub](https://hub.docker.com/r/seatable/seatable-enterprise/). If your SeaTable server has no connection to the internet you need to provide a local container repository like [Quay](https://quay.io) or [Harbor](https://goharbor.io).
The installation, configuration and usage of such a repository if far beyond the scope of this manual.
### Separate local APT repository.
To keep your linux base system up-to-date and to install docker and other software components, you have to provide a local APT repository. This is also not part of this manual to explain how this works.
### Plugins
This is the most easy part because SeaTable provides a way that you download the Plugins as ZIP files to your local PC and then you can upload it from the local network. Read [this article](../../configuration/plugins.md) for more details.
---
Source: https://admin.seatable.com/installation/advanced/webserver-security/
# Security settings
## Accept headers
Our default deployment enforces strict security headers, which prevent the loading of images or scripts from external URLs. This approach is designed to enhance security and protect against fraudulent activities.
If you are running your own server, you have the option to modify these security headers to allow additional sites to interact with your SeaTable server.
To adjust these settings, you can modify the `seatable-server.yml` file located at `/opt/seatable-compose/seatable-server.yml`. The default configuration might look like this:
```yaml
caddy.header.Content-Security-Policy: "`
block-all-mixed-content;
default-src 'none';
style-src 'unsafe-inline' 'self';
script-src 'unsafe-inline' 'unsafe-eval' 'self';
script-src-elem 'unsafe-inline' 'self' ${SEATABLE_SERVER_HOSTNAME}:${ONLYOFFICE_PORT:-6233} maps.googleapis.com;
font-src 'self' data:;
img-src 'self' data: blob: https: market.seatable.io mt0.google.com maps.googleapis.com maps.gstatic.com;
form-action 'self' ${SEATABLE_SERVER_HOSTNAME}:${COLLABORA_PORT:-6232};
connect-src 'self' market.seatable.io https:;
frame-src 'self' ${SEATABLE_SERVER_HOSTNAME}:${COLLABORA_PORT:-6232} ${SEATABLE_SERVER_HOSTNAME}:${ONLYOFFICE_PORT:-6233};
frame-ancestors 'self';
worker-src 'self' blob:;
manifest-src 'self';
object-src 'self';
base-uri 'self'
`"
```
Create a custom copy of your `seatable-server.yml` file and modify these settings according to your specific requirements. Don't forget to link the new yml file in your `.env` file.
## Cookies
To get these ratings, it is required to add two more options to `dtable_web_settings.py`. In one of the next versions, these parameters will probably be added by default.
```bash
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
```
## DNSSEC
It also requires DNSSEC from your domain hoster to get the best security measures.
## IP access restriction
If you want to limit access to your SeaTable Server to selected IP addresses, read [IP Access Restriction](./ip-access-restriction.md).
---
Source: https://admin.seatable.com/installation/advanced/ip-access-restriction/
# IP Access Restriction
By default, your SeaTable Server is accessible from any IP address. This article explains how to limit access to a list of allowed IP addresses (allowlist) or how to block single IP addresses (blocklist). Requests from all other IP addresses are answered with `403 Forbidden`.
The restriction is done by Caddy. You don't have to modify `seatable-server.yml` or `caddy.yml`. Instead, you add one additional yml file and one file containing your IP addresses. This keeps your changes intact during updates.
The restriction applies to every request. Users with a non-allowed IP address can't use any features that are meant to be public, for example:
- Forms (`/dtable/forms/...`)
- External links and shared views
- Universal Apps
- API requests from external services like n8n Cloud, Make or Zapier
Make sure to add the IP addresses of all users and services that need access.
## Configure an allowlist
### Step 1: Create the file with your allowed IP addresses
Create a new directory `caddy-snippets` inside `/opt/seatable-compose` and add a file `ip-allowlist.caddy`:
```bash
mkdir -p /opt/seatable-compose/caddy-snippets
nano /opt/seatable-compose/caddy-snippets/ip-allowlist.caddy
```
Insert the following content and replace the example IP addresses with your own:
```Caddyfile
@blocked {
# Office
not remote_ip 203.0.113.10
# VPN gateway
not remote_ip 198.51.100.0/24
# Home office (multiple addresses can be separated by spaces)
not remote_ip 192.0.2.44 192.0.2.45
# Docker networks, required for components on the same host
not remote_ip private_ranges
}
handle @blocked {
respond 403
}
```
**Explanation**
- Every line `not remote_ip ...` accepts one or more IP addresses or CIDR ranges, separated by spaces.
- All lines must match for a request to be blocked. In other words: a request is blocked if its IP address is not part of any line.
- Lines starting with `#` are comments.
- `private_ranges` covers all private and loopback networks (e.g. `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `127.0.0.0/8`). Components like Collabora Online, OnlyOffice, SeaDoc or the Python Pipeline call your SeaTable Server via its public URL. These requests reach Caddy with an internal Docker IP address and would be blocked without this line.
You might find examples that only use `respond @blocked 403`. Don't use this, it leaves gaps. Caddy executes `route` blocks before `respond`, and some components add routes that forward requests directly to another container. For example, [`seatable-html-server.yml`](../components/html-server.md) adds such a route for `/app-server/*`. With `respond`, this path stays accessible for every IP address. `handle` is executed before `route` and therefore blocks these paths as well.
If your server is located in a private network (e.g. your company LAN), `private_ranges` allows every client from this network. In this case, replace `private_ranges` with the Docker networks only (usually `172.16.0.0/12`) and add the allowed LAN addresses explicitly.
### Step 2: Create `ip-allowlist.yml`
Create a new file `/opt/seatable-compose/ip-allowlist.yml` with the following content:
```yaml
---
services:
caddy:
volumes:
- ./caddy-snippets:/etc/caddy/custom:ro
seatable-server:
labels:
caddy_0.import: /etc/caddy/custom/ip-allowlist.caddy
```
This mounts the directory `caddy-snippets` into the Caddy container and imports your IP list into the configuration of SeaTable Server. Docker Compose merges these settings with `caddy.yml` and `seatable-server.yml`.
Please mount the directory and not only the file. Many editors (like vim) replace a file when saving it. A container with a single-file mount would continue to see the old version of your file.
### Step 3: Add `ip-allowlist.yml` to your `.env` file
`ip-allowlist.yml` must be the **last** entry of the `COMPOSE_FILE` variable inside your `.env` file:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,ip-allowlist.yml'/" /opt/seatable-compose/.env
```
### Step 4: Apply the changes
Run the following command inside `/opt/seatable-compose`:
```bash
docker compose up -d
```
Check the logs of Caddy for errors:
```bash
docker logs caddy 2>&1 | grep -i "invalid block"
```
If your `ip-allowlist.caddy` contains a syntax error, Caddy removes the complete configuration of your SeaTable Server, and SeaTable is no longer accessible. The logs show a message like `Removing invalid block: parsing caddyfile tokens for 'handle' ...`. Fix your file and apply the changes again.
## Test the restriction
Run the following commands from a computer with a non-allowed IP address (e.g. a smartphone hotspot). Replace `seatable.example.com` with your domain:
```bash
curl -s -o /dev/null -w '%{http_code}\n' https://seatable.example.com/
curl -s -o /dev/null -w '%{http_code}\n' https://seatable.example.com/api2/ping/
```
Both commands must return `403`. From an allowed IP address, you get `302` and `200`, and SeaTable works as usual.
## Restrict additional components
Components like Collabora Online or n8n are accessible via their own ports. Each component has its own Caddy configuration, which is not covered by the restriction of SeaTable Server. If you want to restrict these components as well, add their services to `ip-allowlist.yml`. Please note that these services use the label prefix `caddy` instead of `caddy_0`:
```yaml
---
services:
caddy:
volumes:
- ./caddy-snippets:/etc/caddy/custom:ro
seatable-server:
labels:
caddy_0.import: /etc/caddy/custom/ip-allowlist.caddy
collabora:
labels:
caddy.import: /etc/caddy/custom/ip-allowlist.caddy
n8n:
labels:
caddy.import: /etc/caddy/custom/ip-allowlist.caddy
```
These are the service names of the components with their own ports:
| Component | yml file | Service name | Default port |
| ---------------- | ----------------- | --------------- | ------------ |
| Gatus | `gatus.yml` | `gatus` | 6220 |
| Uptime Kuma | `uptime-kuma.yml` | `uptime-kuma` | 6230 |
| n8n | `n8n.yml` | `n8n` | 6231 |
| Collabora Online | `collabora.yml` | `collabora` | 6232 |
| OnlyOffice | `onlyoffice.yml` | `onlyoffice` | 6233 |
| Zabbix | `zabbix.yml` | `zabbix-web` | 6235 |
| tldraw | `tldraw.yml` | `tldraw-worker` | 6239 |
| SeaDoc | `seadoc.yml` | `seadoc` | 6240 |
| Dozzle | `dozzle.yml` | `dozzle` | 6241 |
Only add services whose yml file is part of `COMPOSE_FILE`. Otherwise `docker compose` stops with an error like `service "collabora" has neither an image nor a build context specified`.
[`gatus.yml`](../components/gatus.md) adds a redirect from `/status` to the Gatus port. This redirect is executed before the IP check and therefore stays accessible for every IP address. Add the import to the `gatus` service to protect the status page itself.
## Update the list of IP addresses
Caddy does not notice changes to `ip-allowlist.caddy` automatically. After you have changed the file, reload the configuration of Caddy:
```bash
docker exec caddy caddy reload --config /config/caddy/Caddyfile.autosave --adapter caddyfile
```
The reload applies the new list without any interruption. If your file contains an error, the reload is aborted with an error message and the previous configuration stays active.
Alternatively, you can restart Caddy with `docker compose restart caddy`. This takes a few seconds, your certificates are kept.
## Let's Encrypt
Let's Encrypt keeps working without any further configuration. Caddy answers the ACME challenges for your certificates before your IP check is executed:
- HTTP-01 challenges on port 80 are answered internally by Caddy. The restriction is only added to the HTTPS configuration.
- TLS-ALPN-01 challenges on port 443 are answered during the TLS handshake, before any HTTP rule is evaluated.
There is no need to open the restriction for the IP addresses of Let's Encrypt.
## IPv6
If you only allow IPv4 addresses, make sure your domain has no AAAA record. You can check this with:
```bash
dig AAAA seatable.example.com +short
```
If the command returns an IPv6 address, users with IPv4 and IPv6 connect via IPv6. Caddy sees their IPv6 address, which is not on your list, and blocks them. Either remove the AAAA record or add the IPv6 addresses or ranges of your users to `ip-allowlist.caddy`.
If you use IPv6, IPv6 must be enabled for the Docker network of Caddy. Otherwise, Caddy only sees the IP address of the Docker gateway for every IPv6 request. Read more about this in [Activate IPv6](./ipv6-support.md).
## Configure a blocklist
You can also use the opposite approach and block single IP addresses, while all other IP addresses keep access. Remove the `not` from your `ip-allowlist.caddy`:
```Caddyfile
@blocked {
# Scanner
remote_ip 203.0.113.10 203.0.113.11
# Network of a hosting provider
remote_ip 198.51.100.0/24
}
handle @blocked {
respond 403
}
```
In this case, a request is blocked if its IP address matches **any** of the lines. All other steps are identical.
A blocklist only blocks IP addresses you already know. Every other IP address keeps access, including requests via IPv6 if your domain has an AAAA record. If you need to protect your server against brute-force attacks, consider tools like fail2ban or CrowdSec.
---
Source: https://admin.seatable.com/installation/advanced/maintenance-mode/
# Maintenance Mode
Sometimes updates or changes in the configuration are necessary, and it's important to limit access to the server during this period. Enabling maintenance mode ensures that only dedicated IP addresses can access the server, while all other users see a simple maintenance page with a `503 Service Unavailable` status code.
## Enabling Maintenance Mode
Here's how to configure such a maintenance page using Caddy:
1. Go to `/opt/seatable-compose/`
2. Create a new file `maintenance.yml` with the following content.
3. Replace `` with the IP address that should have access to your server. Multiple IP addresses can be separated by spaces.
4. Open your `.env` file and add `maintenance.yml` as the **last** entry of the variable `COMPOSE_FILE`.
5. Run `docker compose up -d`
```yaml
---
services:
seatable-server:
labels:
caddy_0.@maintenance: "not remote_ip private_ranges"
caddy_0.handle: "@maintenance"
caddy_0.handle.header: "Retry-After 3600"
caddy_0.handle.respond: '"This SeaTable Server is currently undergoing maintenance. The service will be restored shortly. Thank you for your patience." 503'
```
Docker Compose merges these labels with the labels of `seatable-server.yml`, so all other settings like the security headers stay active.
`private_ranges` ensures that components on the same host, like Collabora Online or the Python Pipeline, can still reach your SeaTable Server.
Older versions of this article used `respond` without `handle`. With this configuration, paths that are routed to other containers (e.g. `/app-server/*` of the [HTML server](../components/html-server.md)) stayed accessible during the maintenance. `handle` blocks these paths as well. Read more in [IP Access Restriction](./ip-access-restriction.md).
## How does maintenance look like
If you are accessing your system from an IP address that has been specified in your labels, you can continue using SeaTable as usual.
All other users will see a maintenance page displaying the following message:

## Disable Maintenance Mode
To disable maintenance mode, remove `maintenance.yml` from the variable `COMPOSE_FILE` in your `.env` file. Then, run the command:
```bash
docker compose up -d
```
Your SeaTable server will once again be accessible to all users.
---
Source: https://admin.seatable.com/installation/advanced/settings-caddy/
# Advanced Settings for Caddy
## Enabling Logging for Caddy Docker Proxy
To enable logging for the Lucas Lorentz Caddy Docker Proxy, you need to add a label to the **service container** (not the proxy container itself). For SeaTable Server, you can activate logging by adding the `caddy.log` label to your `seatable-server.yml` file.
**Example Configuration**
```bash
---
services:
seatable-server:
...
labels:
caddy: ${SEATABLE_SERVER_PROTOCOL:-https}://${SEATABLE_SERVER_HOSTNAME:?Variable is not set or empty}
# new: activate logs
caddy.log:
caddy.reverse_proxy: "{{upstreams 80}}"
...
```
**Explanation**
This label `caddy.log:` enables logging for the service and outputs logs to `stdout`. Once configured, you can view the logs using standard Docker commands, such as `docker logs ` or `docker compose logs seatable-server`.
These logs are specific to the service container (e.g., SeaTable Server). To view logs for the Caddy proxy itself, check the logs of the Caddy proxy container.
## Preserve the Original Client IP Behind a Front Proxy
If there is an additional reverse proxy (for example, a company-wide load balancer or a Cloudflare proxy) placed in front of your Caddy instance, you may notice that the SeaTable logs, web interface, or the underlying Nginx access logs only show the proxy’s IP address instead of the real client IP. This happens because Caddy treats the front proxy as the client and therefore forwards its IP instead of the external user's one.
To fix this, you can configure Caddy to forward the original client’s IP address using the `X-Forwarded-For` header.
**Example Configuration**
```bash
---
services:
seatable-server:
...
labels:
caddy: ${SEATABLE_SERVER_PROTOCOL:-https}://${SEATABLE_SERVER_HOSTNAME:?Variable is not set or empty}
caddy.reverse_proxy: "{{upstreams 80}}"
# new: forward external ip to seatable nginx
caddy.reverse_proxy.header_up: "X-Forwarded-For {http.request.header.X-Forwarded-For}"
```
**Explanation**
The label `caddy.reverse_proxy.header_up: "X-Forwarded-For {http.request.header.X-Forwarded-For}"` instructs Caddy to copy the existing `X-Forwarded-For` header from the incoming HTTP request (added by the front proxy) and send it to the SeaTable Nginx container. As a result, SeaTable and its embedded Nginx will correctly log and display the original client IP address instead of the proxy’s IP.
If there is no such header from the front proxy, Caddy will automatically generate one with the client’s own address. This ensures that IP forwarding works as expected in both single-proxy and multi-proxy setups.
---
## SeaTable AI
Source: https://admin.seatable.com/installation/advanced/seatable-ai-standalone/
# Standalone Deployment of SeaTable AI
This guide describes the standalone deployment of `seatable-ai` on a dedicated server or virtual machine.
## Prerequisites
- You have successfully installed [Docker and Docker-Compose](../basic-setup.md#install-docker-and-docker-compose-plugin)
- You have [downloaded the latest `.yml` files](../basic-setup.md#create-basic-structure) from the `seatable-release` GitHub repository
- The hosts destined to run `seatable-ai` and other SeaTable components are attached to the same private network
## SeaTable AI Configuration
The following section outlines an `.env` file with the settings needed to run `seatable-ai`.
These changes should be made inside `/opt/seatable-compose/.env`:
```ini
COMPOSE_FILE='seatable-ai-standalone.yml'
COMPOSE_PATH_SEPARATOR=','
# system settings
TIME_ZONE='Europe/Berlin'
# database
MARIADB_HOST=
MARIADB_PORT=3306
MARIADB_PASSWORD=
# redis
REDIS_HOST=
REDIS_PORT=6379
REDIS_PASSWORD=
# This private key must have the same value as the JWT_PRIVATE_KEY variable on other SeaTable nodes
JWT_PRIVATE_KEY=
SECRET_KEY=
# Public URL of your SeaTable server
SEATABLE_SERVER_URL=https://seatable.your-domain.com
# Cluster-internal URL of dtable-server
INNER_DTABLE_SERVER_URL=http://dtable-server:5000
# Cluster-internal URL of dtable-db
INNER_DTABLE_DB_URL=http://dtable-db:7777
```
By default, the ports of `dtable-server` (5000) and `dtable-db` (7777) are not exposed to the host. This requires a manual change inside the `.yml` file.
### LLM Provider Configuration
Please refer to the documentation on [configuring your LLM provider of choice](../components/seatable-ai.md#llm-provider-configuration).
These configuration details do not change depending on the deployment topology of `seatable-server` and `seatable-ai`.
### Start SeaTable AI
You can now start SeaTable AI by running the following command inside your terminal:
```bash
cd /opt/seatable-compose
docker compose up -d
```
## Configuration of SeaTable Server
Since `seatable-ai` is now running on a separate host or virtual machine, the following configuration changes must be made inside the `.env` file on the host running the `seatable-server` container:
```ini
ENABLE_SEATABLE_AI=true
INNER_SEATABLE_AI_SERVER_URL='http://seatable-ai.example.com:8888'
```
Restart the `seatable-server` service and test your SeaTable AI:
```bash
cd /opt/seatable-compose
docker compose up -d
```
---
Source: https://admin.seatable.com/installation/advanced/seatable-ai-token-pricing/
# AI Token Pricing
## AI Credits
AI credits serve as an internal unit of currency for measuring AI-related usage within SeaTable.
They are directly linked to the number of tokens consumed by using AI-based features according to the [configured price](#pricing-configuration) of each AI model.
SeaTable supports role-based AI credit limits by configuring the `ai_credit_per_user` option on a user role.
Please refer to the documentation on [user quotas](../../configuration/roles-and-permissions.md#user-quotas) for more details.
AI credits are shared across all users inside a SeaTable organization. The total number of credits can be calculated by multiplying the value of `ai_credit_per_user` by the number of team users.
**Example:** Setting `ai_credit_per_user` to `2` will allow a team with 10 members to have 20 AI credits in total.
## Pricing Configuration
In order to accurately track the number of AI credits used by users and organizations, you must configure token pricing.
The configuration approach depends on your SeaTable version:
### SeaTable v6.0 + v6.1
Token pricing is configured inside `/opt/seatable-server/seatable/conf/dtable_web_settings.py`.
This can be achieved by configuring the `AI_PRICES` variable, which is a dictionary that maps model identifiers (e.g `gpt-4o-mini`) to token pricing **per thousand tokens**:
```py
AI_PRICES = {
"gpt-4o-mini": {
"input_tokens_1k": 0.01827, # price / 1000 tokens
"output_tokens_1k": 0.07309 # price / 1000 tokens
},
}
```
The dictionary key must match **the exact value** of the chosen AI Model, which is configured through the `SEATABLE_AI_LLM_MODEL` variable inside your `.env` file.
In case of a mismatch, AI usage will not count towards any configured credit limits!
### SeaTable v6.2+
Token pricing is configured inside `/opt/seatable-server/seatable/conf/seatable_config.yaml`.
If the file does not exist yet, simply create it.
Since version 6.2, token pricing is configured **per 1 million tokens** (previously: per 1000 tokens).
This change aligns SeaTable's behavior with the behavior of most other AI-enhanced applications.
```yaml
global:
LLM_MODELS:
- type: ...
key: ...
model: ...
price:
# Price per 1M tokens
input_tokens: 1
output_tokens: 5
```
Remember to restart the `seatable-server` container (since token pricing is handled by `dtable-events`, which runs inside the `seatable-server` container) by running the following command:
```bash
cd /opt/seatable-compose
docker compose up -d --force-recreate seatable-server
```
**Note:** The `--force-recreate` flag ensures that the container is restarted even if its `.yml` file or environment variables haven't changed.
---
## LLM Self-Hosting
Source: https://admin.seatable.com/installation/advanced/seatable-ai-prerequisites/
# Prerequisites
This following guides assume that you have a fully functioning [SeaTable Server installation](../basic-setup.md) and have successfully installed [SeaTable AI](../components/seatable-ai.md).
Running an LLM requires significant computing resources.
While the exact requirements depend on the chosen model, our internal tests have shown that LLMs with less than 8 billion parameters do not yield useful results for the use cases we looked at.
Therefore, we recommend that you choose a model with **at least 8-12 billion parameters**.
Generally speaking, this will require **at least 16GB of VRAM** (or more, depending on the configured context window size).
While you can run AI models on a CPU, performance (measured in tokens per second) will be much worse compared to running the same model on a powerful GPU.
## GPU Usage
You can refer to [Ollama's documentation](https://github.com/ollama/ollama/blob/main/docs/docker.md) for instructions regarding GPU usage.
Depending on your GPU, this will require installing proprietary NVIDIA drivers and the NVIDIA Container Toolkit or adding additional arguments to the `.yml` files shown in the following guides.
For **Debian**-based systems with **NVIDIA** GPUs, the following steps were carried out to successfully deploy [Ollama](./ollama.md) and [vLLM](./vllm.md):
1. Install the proprietary NVIDIA drivers. The [Debian Wiki](https://wiki.debian.org/NvidiaGraphicsDrivers) contains installation instructions for the latest Debian releases.
2. Remember to restart your system before proceeding with the following steps.
3. Install the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html).
---
Source: https://admin.seatable.com/installation/advanced/ollama/
# Ollama
[Ollama](https://docs.ollama.com/) is a framework that allows you to run various LLMs (Large Language Models) on your own hardware.
This guides showcases a **very basic** Ollama deployment meant for trying out a self-hosted LLM deployed on the same server as SeaTable itself.
You should take a look at [vLLM](./vllm.md) in case you plan on deploying a **production-ready** LLM inference/serving engine.
Compared to Ollama, vLLM provides much better performance when handling concurrent requests.
## Instructions
### Create `ollama.yml`
Create `/opt/seatable-compose/ollama.yml` with the following contents:
```yaml
services:
ollama:
image: ollama/ollama:0.11.10
restart: unless-stopped
container_name: ollama
# Comment out the following line if you don't have a GPU
gpus: all
networks:
- backend-seatable-net
volumes:
- /opt/ollama:/root/.ollama
```
Afterwards, you should add `ollama.yml` to the `COMPOSE_FILE` variable inside your `.env` file:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,ollama.yml'/" /opt/seatable-compose/.env
```
### Configuration
Please refer to the [LLM provider configuration](../components/seatable-ai.md#llm-provider-configuration) docs.
The URL must be set to `http://ollama:11434` in case you're deploying Ollama on the same host/VM as SeaTable.
### Start Ollama
You can now start Ollama by running `docker compose up -d` inside `/opt/seatable-compose`.
In addition, it is necessary to manually download the chosen AI model by executing the following command **once**:
```bash
docker exec -it ollama ollama pull $MODEL
```
You are now able to run AI-based automations steps inside SeaTable via your local Ollama deployment!
---
Source: https://admin.seatable.com/installation/advanced/vllm/
# vLLM
[vLLM](https://docs.vllm.ai/en/stable/) is an inference and serving engine for LLMs (Large Language Models) that allows you to run AI models on your own hardware.
Compared to [Ollama](./ollama.md), vLLM provides better throughput under high-concurrency scenarios.
Ensure that GPU drivers are correctly installed on your GPU server **and** that they can be passed through to Docker.
These steps depend on your specific environment and are **not covered** in this guide.
Also verify that your setup meets all [requirements](./seatable-ai-prerequisites.md).
In the sample `vllm.yml` provided for vLLM, the NVIDIA runtime is already configured.
Review and adjust this configuration if your system requires different runtime settings.
## Additional Prerequisites
### HuggingFace Access Token
By default, vLLM will try to download models from [HuggingFace](https://huggingface.co).
Some models are only available after accepting license or usage terms.
This requires you to [generate an access token](https://huggingface.co/docs/hub/security-tokens) that can be used to download models.
You should store this access token in a safe location since it cannot be displayed again.
## Instructions
### Download `.yml` files
Download the latest `.yml` from GitHub by running the following command:
```bash
mkdir /opt/seatable-compose && \
cd /opt/seatable-compose && \
wget -c https://github.com/seatable/seatable-release/releases/latest/download/seatable-compose.tar.gz -O - | tar -xz -C /opt/seatable-compose && \
cp -n .env-release .env
```
### Create `vllm.yml`
Create `/opt/seatable-compose/vllm.yml` with the following contents:
```yaml
services:
vllm:
image: vllm/vllm-openai:v0.11.0
container_name: vllm
restart: unless-stopped
runtime: nvidia
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
ipc: host
command: ["--model", "${VLLM_MODEL:?Variable is not set or empty}", "--enable-log-requests", "--max-model-len", "${VLLM_MAX_MODEL_LEN:-65536}"]
environment:
- HUGGING_FACE_HUB_TOKEN=${HUGGING_FACE_TOKEN:?Variable is not set or empty}
- VLLM_API_KEY=${VLLM_API_KEY:?Variable is not set or empty}
# If set to true, enables logging of all API server responses from vLLM. Don't use this in production.
- VLLM_DEBUG_LOG_API_SERVER_RESPONSE=${VLLM_DEBUG_LOG_API_SERVER_RESPONSE:-false}
networks:
- frontend-net
volumes:
- ~/.cache/huggingface:/root/.cache/huggingface
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 10s
start_period: 300s
logging:
driver: json-file
options:
# Maximum size per file
max-size: 10m
# Maximum number of files
max-file: 3
labels:
caddy: ${VLLM_HOSTNAME:?Variable is not set or empty}
caddy.@denied.not_0: "remote_ip ${VLLM_ALLOWED_IPS:?Variable is not set or empty} private_ranges"
caddy.abort: "@denied"
caddy.reverse_proxy: "{{upstreams 8000}}"
```
Afterwards, you should add `vllm.yml` to the `COMPOSE_FILE` variable inside your `.env` file:
```bash
sed -i "s/COMPOSE_FILE='\(.*\)'/COMPOSE_FILE='\1,vllm.yml'/" /opt/seatable-compose/.env
```
Make sure that `COMPOSE_FILE` already includes `caddy.yml` since vLLM's port 8000 is not exposed by default.
### vLLM Configuration
Add the following configuration settings to your `.env` file to configure vLLM:
```ini
VLLM_HOSTNAME='YOUR_VLLM_HOSTNAME'
# Allowed IP addresses (multiple addresses can be separated by spaces)
VLLM_ALLOWED_IPS='SEATABLE_AI_PUBLIC_IP'
# Set this to a long random string, e.g. generated by "pwgen -s 64 1"
# This API key must then be used for any API requests
VLLM_API_KEY=''
HUGGING_FACE_TOKEN='YOUR_HUGGING_FACE_TOKEN'
# Model identifier from HuggingFace
# (e.g. RedHatAI/gemma-3-12b-it-quantized.w4a16)
VLLM_MODEL=''
```
### Start vLLM
You can start vLLM by running the following command inside `/opt/seatable-compose`:
```bash
docker compose up -d
```
Starting vLLM may take several minutes depending on the model size and computing resources.
On first startup, vLLM will automatically download the configured model from [HuggingFace](https://huggingface.co).
Wait for the Docker container to report a healthy status before proceeding.
Perfect! Your local vLLM deployment is ready to use.
## SeaTable AI Configuration
Please refer to the [LLM provider configuration](../components/seatable-ai.md#llm-provider-configuration) docs.
**Note:** The type must be set to `hosted_vllm` and the URL must be set to `https:///v1` when using vLLM for AI-based automations within SeaTable.
Remember to restart SeaTable AI after making any changes.
## Test vLLM
### Send a request
You can send your first request to vLLM with the following example from the command line of the host/VM that runs the **SeaTable AI container**.
This makes sure that the IP address of SeaTable AI is part of the list of allowed IP addresses configured with `VLLM_ALLOWED_IPS`.
Make sure to replace `YOUR_VLLM_HOSTNAME`, `YOUR_VLLM_KEY` and `YOUR_VLLM_MODEL` with the appropriate values:
```bash
docker exec -i seatable-ai bash -s <`.
Security header configuration in your `seatable-server.yml` might prevent this and you need your S3 url to the Content-Security-Policy.
```text
caddy.header.Content-Security-Policy:
...
img-src 'self' data: blob: ...
```
While other S3 buckets used by SeaTable can remain private, the S3 bucket for avatars must be publicly readable. Once avatars are saved to S3, they are accessed directly from the S3 storage. Therefore, it is necessary to grant read access to everyone (anonymous access) while restricting write access to authenticated users with bucket credentials.
---
Source: https://admin.seatable.com/installation/advanced/s3-encryption/
# S3 Encryption
SeaTable supports **SSE-C** (server-side encryption with customer-provided keys) to encrypt objects stored inside the S3 buckets **at rest**.
This applies to both base snapshots and the content of file and image columns.
Please note that certain object storage providers that are based on Ceph (e.g. Hetzner Object Storage) currently do not support `CopyObject` operations when using SSE-C. This makes them incompatible with SeaTable. There is an [open issue](https://tracker.ceph.com/issues/23264) over at the Ceph issue tracker.
## Configuration
### Key Generation
SeaTable requires an encryption key that is exactly 32 characters long.
You can generate a valid key with the following command:
```bash
openssl rand -base64 24
```
You should make sure to store the encryption key in a safe location. Losing the key will result in permanent data loss of all encrypted objects.
Since the cloud storage provider does not store the key (instead, SeaTable provides the key with every request), there's no way to recover the data since the actual objects are encrypted at rest.
CLI tools such as [`mc`](https://docs.min.io/community/minio-object-store/reference/minio-mc.html) will reject a key generated using the `openssl` command displayed above.
They require you to encode the key as base64.
This can be achieved with the following command:
```bash
# printf ensures that there's no trailing newline character
printf 'KEY_GENERATED_BY_OPENSSL' | base64
```
In addition, you must **strip** any trailing `=` signs at the end of the key that are used for padding before passing the key to `mc` commands such as `mc put` or `mc get`.
### Environment Variables
From version 6.1 onwards, SeaTable supports reading S3 configuration from environment variables.
The previous approach [via configuration files](#configuration-files-legacy) is only supported until (and including) version 6.1.
Using environment variables has numerous advantages:
- All relevant credentials are configured inside your `.env` file instead of being distributed between different configuration files
- Configuration based on environment variables allows for a declarative deployment using S3, which was not previously possible
- Docker-Compose automatically detects changes to the values of environment variables when running `docker compose up -d` and restarts any dependent services
Please note that the approach based on environment variables **does not allow** configuring different encryption keys for the different buckets used by SeaTable.
Enabling SSE-C encryption via the `S3_SSE_C_KEY` environment variable **will enable SSE-C encryption** for base snapshots, files **and** assets.
Configuring the encryption key via an environment variable requires S3 configuration via environment variables (see [this page](./s3.md#environment-variables) for details).
To enable SSE-C encryption, simply set the `S3_SSE_C_KEY` inside your `.env` file to the value of the generated encryption key.
You must restart SeaTable after applying this configuration change:
```bash
docker compose up -d
```
### Configuration Files (Legacy)
`dtable-storage-server.conf` will not be read anymore after upgrading from v6.1 to v6.2.
Please use [environment variables](#environment-variables) instead to configure S3 encryption.
Instead of using environment variables, you can also use the previous approach of configuring the encryption key inside the configuration files.
To encrypt both base snapshots and assets, you must configure a valid encryption key in **two locations**:
- `dtable-storage-server.conf` to encrypt base snapshots
- `seafile.conf` to encrypt the files stored in file and image columns
These encryption keys can be different.
#### Base Snapshots
To encrypt base snapshots at rest, you must configure an encryption key inside `dtable-storage-server.conf`:
```ini
[storage backend]
# ...
sse_c_key = YOUR_ENCRYPTION_KEY
```
You must restart SeaTable after applying this configuration change:
```bash
docker restart seatable-server
```
#### Assets
To encrypt the file assets stored in file and image columns, you must configure an encryption key inside `seafile.conf` for all three object types (commits, fs and blocks):
```ini
[commit_object_backend]
# ...
sse_c_key = YOUR_ENCRYPTION_KEY
[fs_object_backend]
# ...
sse_c_key = YOUR_ENCRYPTION_KEY
[block_backend]
# ...
sse_c_key = YOUR_ENCRYPTION_KEY
```
You must restart SeaTable after applying this configuration change:
```bash
docker restart seatable-server
```
## Migration
Any objects stored **before** enabling SSE-C won't be accessible after restarting SeaTable since SeaTable does not keep track whether a certain object is encrypted or not.
This requires you to manually encrypt the objects with the configured encryption key.
The easiest way to achieve this is to copy all objects to separate buckets with enabled encryption.
However, certain object storage providers such as [Exoscale](https://community.exoscale.com/product/storage/object-storage/how-to/encryption/#limitations) do not support mirroring objects between buckets with differing encryption configuration settings.
As a workaround, you can **download** all objects to the local filesystem **before** uploading them again with enabled encryption.
This can be achieved with the following `mc` commands:
```bash
mc mirror ${ALIAS}/block1 /tmp/block1 --summary
mc mirror /tmp/block1 ${ALIAS}/block2 --summary --enc-c "${ALIAS}/block2/=${ENCRYPTION_KEY}"
mc mirror ${ALIAS}/commit1 /tmp/commit1 --summary
mc mirror /tmp/commit1 ${ALIAS}/commit2 --summary --enc-c "${ALIAS}/commit2/=${ENCRYPTION_KEY}"
mc mirror ${ALIAS}/fs1 /tmp/fs1 --summary
mc mirror /tmp/fs1 ${ALIAS}/fs2 --summary --enc-c "${ALIAS}/fs2/=${ENCRYPTION_KEY}"
mc mirror ${ALIAS}/storage1 /tmp/storage1 --summary
mc mirror /tmp/storage1 ${ALIAS}/storage2 --summary --enc-c "${ALIAS}/storage2/=${ENCRYPTION_KEY}"
```
- `${ALIAS}` refers to the configured `mc` alias
- `block1`, `commit1`, `fs1` and `storage1` refer to the old buckets with **unencrypted** objects
- `block2`, `commit2`, `fs2` and `storage2` refer to the new buckets that contain **encrypted** objects
Afterwards, you must update the bucket names inside `dtable-storage-server.conf` and `seafile.conf` and restart SeaTable to apply the configuration changes:
```bash
docker restart seatable-server
```
In case you're using environment variables in order to configure S3, you'll have to update the bucket names and apply the configuration changes by running the following command inside `/opt/seatable-compose`:
```bash
docker compose up -d
```
---
## Python Pipeline
Source: https://admin.seatable.com/installation/advanced/python-pipeline-custom-python-runner/
# Create your own SeaTable Python Runner
The SeaTable Python Pipeline includes a pre-configured python-runner image with numerous third-party Python libraries to execute your scripts. For a complete list of the included libraries, refer to the [Developer Manual](https://developer.seatable.com/scripts/python/common_questions/#install-and-use-custom-python-libraries).
If you require additional Python packages, you can either contact support to request their inclusion in future versions or build your own custom image by extending the existing one.
## Build your own custom python runner image
This guide assumes you will create the custom Python runner image directly on your server. If you choose to build it locally, you must push the custom image to an image registry (e.g., Docker Hub), which is outside the scope of this guide.
### Step 1: Create a `Dockerfile`:
Create a `Dockerfile` with the following content:
```Dockerfile
# You can find the latest tag here: https://hub.docker.com/r/seatable/seatable-python-runner/tags
# or simply use the "latest" tag.
FROM seatable/seatable-python-runner:latest
# Install your custom-packages with pip
RUN pip install --user --no-cache-dir \
pypdf \
pytesseract \
# Replace with your required packages
```
### Step 2: Build your Image
Run the following command to build your image. Use the `-t` option to specify a custom name and tag:
```bash
docker build . -t custom-python-runner:1.0
```
### Step 3: Configure SeaTable to Use Your Custom Image
Update your `/opt/seatable-compose/.env` file to specify your custom Python runner image:
```ini
PYTHON_RUNNER_IMAGE='custom-python-runner:1.0'
```
After updating the .env file, restart your SeaTable setup with:
```bash
docker compose up -d
```
You can verify that your custom image is being used by running:
```bash
docker ps
```
### Step 4: Verify Installed Packages
Run this Python script within SeaTable to confirm that your required packages are available:
```python
import importlib.metadata
distributions = importlib.metadata.distributions()
installed_packages = [dist.metadata['Name'] for dist in distributions]
print(installed_packages)
```
This script will display a list of installed Python packages.

## Important Considerations
By creating a custom Python runner image, you forgo automatic updates. When a new base image version is released, manually rebuild your custom image to incorporate the latest changes.
While installing additional Python packages won't significantly slow down your Python Docker Runner, it will:
- Increase the container's size
- Potentially increase memory usage
These factors may affect deployment time and resource allocation, but usually won't impact runtime performance noticeably.
---
Source: https://admin.seatable.com/installation/advanced/python-pipeline-dedicated-server/
# Python Pipeline on a separate server
If your user base on your Seatable Server is growing, one of the first components that you could move to a separate server is the python pipeline. This frees up resources for the main server and it increases the security because customer python code is not executed on the main server.
## Requirements
To install Python Pipeline on a separate server, use at least these resources:
- 2 CPU
- 4 GB RAM
- 40 GB SSD
Use a separate domain or subdomain that is public available or you need a valid wildcard certificate.
Caddy will generate a let's encrypt certificate.
Self signed certificates are not recommended. Read the article about [custom certificates](./custom-certificates.md) for more details.
Please configure a firewall to only allow access to port 80 and 443.
These ports are required in order to receive a certificate from Let's Encrypt.
The value of the variable `SEATABLE_SERVER_PUBLIC_IP` is used by Caddy to restrict access to the `python-scheduler` on layer 7.
Only the virtual machine running `dtable-web` should be allowed to access the python-scheduler component.
The Python pipeline should **not** be deployed on a virtual machine that is attached to a private network since the script containers can
access this network interface if you do not configure any additional firewall rules.
## Deployment of the Python Pipeline
The deployment of a separate python pipeline is simple. Get seatable-release from github like described in the installation of seatable server and only use `caddy.yml` and `python-pipeline-standalone.yml`.
Update your `.env`, that it looks like this and add/update the values according to your needs:
```ini
COMPOSE_FILE='caddy.yml,python-pipeline-standalone.yml'
COMPOSE_PATH_SEPARATOR=','
# system settings
TIME_ZONE='Europe/Berlin'
# seatable server url
SEATABLE_SERVER_HOSTNAME=seatable.your-url.com
# database
MARIADB_PASSWORD=your-password
# python-pipeline-standalone
PYTHON_SCHEDULER_HOSTNAME=python.your-url.com
PYTHON_SCHEDULER_AUTH_TOKEN=shared secret with dtable_web_settings.py
# Only this IP is allowed to access the python-scheduler
SEATABLE_SERVER_PUBLIC_IP='IP of seatable.your-url.com'
```
Execute `docker compose up -d` to fire up your separate python pipeline.
## Configuration of SeaTable Server
SeaTable must know how to access the Python Pipeline.
Update the `.env` on the seatable server and add these variables:
```ini
ENABLE_PYTHON_SCRIPT=true
PYTHON_SCHEDULER_URL=https://python.your-url.com
PYTHON_SCHEDULER_AUTH_TOKEN=shared secret with python scheduler
```
Restart the `seatable-server` service by running `docker compose up -d` and test your python pipeline.
---
Source: https://admin.seatable.com/installation/advanced/python-pipeline-configuration/
## Configuration
The Python Pipeline can be configured through environment variables for further customization. The available parameters inside your `.env` file are:
Python scripts execute as user-supplied code. Beyond the parameters below, review the [security considerations on the installation page](../components/python-pipeline.md#installation) — in particular the risk of scripts reaching the cloud metadata endpoint and harvesting the host's machine-identity credentials.
### Resources
| Parameter | Description | Default |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- |
| `PYTHON_PROCESS_TIMEOUT` | The timeout for a single script (in seconds) | `60` |
| `PYTHON_TRANSFER_DIRECTORY_PATH` | The directory on the host where python-starter creates a folder for each individual script job | `/tmp` |
| `PYTHON_RUNNER_CONTAINER_CPUS` | The number of CPUs available to each script container | `1` |
| `PYTHON_RUNNER_CONTAINER_MEMORY` | The amount of memory available to each script container | `1g` |
| `PYTHON_RUNNER_READ_ONLY_FILESYSTEM` | Whether the root filesystem should be mounted as read-only (`true` or `false`) | `true` |
| `PYTHON_RUNNER_TMPFS_MOUNT_SIZE_IN_BYTES` | Maximum size of the `tmpfs` mount (mounted at `/tmp` inside the container) for each script container (in bytes) | `104857600` (100MB) |
| `PYTHON_RUNNER_DROPPED_CAPABILITIES` | Comma-separated list of capabilities that should be removed from the container. Please refer to the [Docker documentation](https://docs.docker.com/engine/containers/run/#runtime-privilege-and-linux-capabilities) for more details | `CAP_NET_RAW` |
| `PYTHON_RUNNER_NO_NEW_PRIVILEGES` | Whether container processes should be prevented from gaining additional privileges | `true` |
### Logging
| Parameter | Description | Default |
| ---------------------------- | ------------------------------------------------------------------------------------------ | --------- |
| `PYTHON_SCHEDULER_LOG_LEVEL` | The log level for the python-scheduler (`DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL`) | `WARNING` |
| `PYTHON_STARTER_LOG_LEVEL` | The log level for the python-starter (`DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL`) | `WARNING` |
## Limiting Volume Size
By default, any script container can use up all of the available storage resources on your disk.
You can use the following instructions to set a limit for the directory that contains all volumes. These commands should be executed on your host.
```bash
# Create an empty file
touch python-pipeline-volume
# Resize the file (e.g. 2GB)
truncate -s 2G python-pipeline-volume
# Create a new ext4 filesystem
mke2fs -t ext4 -F python-pipeline-volume
# Create a new directory which will serve as the data transfer directory
mkdir /opt/python-pipeline-transfer
# Mount the filesystem
mount python-pipeline-volume /opt/python-pipeline-transfer
# Validate your changes
df -h /opt/python-pipeline-transfer
```
Afterwards, you should update your `.env` file and restart the python-starter by running `docker compose up -d`:
```ini
PYTHON_TRANSFER_DIRECTORY_PATH='/opt/python-pipeline-transfer'
```
## Mounting Additional Directories
If your `python-runner` containers require access to an additional host directory, you can use the environment variable `PYTHON_RUNNER_OTHER_OPTIONS` to specify additional arguments for the generated `docker run` command that is used to start the `python-runner` containers.
However, this variable is not part of the `python-pipeline.yml` file by default.
You should therefore create an additional `custom-python-pipeline.yml` file with the following contents to extend the default definition of the `python-starter` service.
Docker Compose will automatically merge these two definitions together.
You can read [our guide](../../configuration/customizations.md) for more information regarding this topic.
```yaml
services:
python-starter:
environment:
- PYTHON_RUNNER_OTHER_OPTIONS=["--volume=/path-on-the-host:/path-inside-the-container:rw"]
```
You should make sure that there are no additional quotes around the square brackets (`[` and `]`) since this will cause issues.
Afterwards, add `custom-python-pipeline.yml` to the `COMPOSE_FILE` variable inside your `.env` file and restart the `python-starter` container by running `docker compose up -d`.
### Troubleshooting
Set `PYTHON_STARTER_LOG_LEVEL` to `DEBUG` inside your `.env` file.
This will cause the full `docker run` command to be logged to STDOUT, which can be retrieved by running `docker compose logs -f python-starter`.
---
Source: https://admin.seatable.com/installation/advanced/python-pipeline-workflow/
# Workflow of the Python Pipeline in a nutshell
This is a short explanation what happens, if you click on "Run script" inside SeaTable.
## SeaTable Server
To initialize the Python Pipeline, SeaTable-Server makes a POST request to the API-endpoint `/run-script/` of the scheduler. This call is authenticated by the shared secret, defined in `dtable_web_settings.py`. Every two seconds (and for max. 15 minutes), the SeaTable Server checks the status of the script execution by calling `/run-script/` from the scheduler.
## SeaTable Scheduler
The scheduler creates a new task in the mariadb database. The scheduler calls the API-endpoint `/function/run-python` of the starter. Now the scheduler waits for the starter's POST request to `/script-result/`, which indicates that the run has finished. The scheduler then writes the duration and the output to the database.
## SeaTable Starter
The starter downloads the python script directly from SeaTable Server and saves the script to a temporary folder on the hard drive of the host. The starter now starts a python-runner container and mounts the script as input. After completion the runner container is deleted and the result data is sent to the scheduler by making a POST request to `/script-result/`.
## SeaTable Runner
SeaTable runner executes the python script and writes the output to the same temporary folder on the host. After that the container stops.
## Important points
- dtable-web only queries the result as long as the browser is open (manual execution).
- if an automation starts a python script, SeaTable Server waits max. 15 minutes for the run to finish.
- starter and runner communicate via the exchange directory. this must be available as a volume to both containers
- starter and scheduler communicate via api calls.
- the python runner is stopped after 15 minutes at the latest
- the scheduler has a cleanup process to invalidate work orders in the database that run for longer than 15 minutes.
- the task is stored in the database for some days (30 days by default)
---
## Network Issues
Source: https://admin.seatable.com/installation/advanced/hairpin-nat/
# Running SeaTable without Hairpin NAT
Some networks and routers do not support hairpin NAT (also called NAT loopback or NAT reflection). This prevents Docker containers from resolving and accessing SeaTable via its external hostname from within the local network. Without a workaround, this breaks internal container-to-container communication, causing failures like Python scripts (e.g., automation tasks) and PDF generation to stop working.
The workaround is to install a local DNS service `dnsmasq`, set up a DNS resolution for the url of your seatable server and then to configure that all docker containers use this dns service.
## Step 1: Install and Configure dnsmasq
Install dnsmasq and create a configuration that resolves your SeaTable hostname locally to the container's gateway IP.
```bash
# Ubuntu/Debian
sudo apt update
sudo apt install dnsmasq
# Add SeaTable hostname resolution (replace 'seatable.example.com' and gateway IP)
echo "address=/seatable.example.com/172.17.0.1" >> /etc/dnsmasq.conf
# Restart dnsmasq
sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq
```
## Step 2: Configure Docker Daemon
Edit Docker's configuration and add the following configuration to use the local dnsmasq as resolver. If the file `/etc/docker/daemon.json` does not exist, create it.
Instead of `8.8.8.8` you can use any other public DNS server.
```bash
{
"dns": ["127.0.0.1", "8.8.8.8"]
}
```
After saving, restart docker with `sudo systemctl restart docker`
## Step 3: Verify and Restart SeaTable
Test resolution inside a container and restart SeaTable.
```bash
# Test DNS resolution (should resolve to gateway IP)
docker run --rm --dns 127.0.0.1 busybox nslookup seatable.example.com
# Restart all containers
cd /opt/seatable-compose
docker-compose down
docker-compose up -d
```
## Troubleshooting
- Check dnsmasq logs: `journalctl -u dnsmasq?`.
- Verify `DTABLE_SERVER_URL` in `dtable_web_settings.py` uses the external hostname only.
- Ensure no conflicting DNS servers on port 53; stop `systemd-resolved` if needed: `sudo systemctl disable --now systemd-resolved`.
This setup ensures all containers resolve the SeaTable hostname correctly without hairpin NAT.
---
## Advanced Topics
Source: https://admin.seatable.com/installation/advanced/metrics/
# Metrics
Metrics give insight into a system's health. In addition, they allow detection of changes happening over time.
Automatic alerts (e.g. by using [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/)) can be configured to provide notifications in case of error conditions or incidents.
Currently, the following SeaTable components expose metrics in a [Prometheus](https://prometheus.io/)-compatible format:
- api-gateway
- dtable-db
- caddy
In addition, **Gunicorn**, **NGINX** and **Redis** can be configured to expose metrics in a different format. Exporters can be used to transform these into a Prometheus-compatible format.
## SeaTable Components
### api-gateway
Please refer to the [api-gateway docs](../../configuration/components/dtable-api-gateway.md#metrics) for instructions on how to enable metrics.
You can test the metrics endpoint by running the following command on the host:
```bash
curl -sS https://$SEATABLE_SERVER_HOSTNAME/api-gateway/metrics --user ":"
```
Example Output
```text
# HELP api_gateway_base_cache_hit_ratio Total base cache hit ratio
# TYPE api_gateway_base_cache_hit_ratio gauge
api_gateway_base_cache_hit_ratio 0.6086956521739131
# HELP api_gateway_base_cache_hit_total Total base cache hit number
# TYPE api_gateway_base_cache_hit_total counter
api_gateway_base_cache_hit_total 14
# HELP api_gateway_base_cache_miss_total Total base cache miss number
# TYPE api_gateway_base_cache_miss_total counter
api_gateway_base_cache_miss_total 9
# HELP api_gateway_obj_cache_eviction_number Total obj cache eviction number
# TYPE api_gateway_obj_cache_eviction_number counter
api_gateway_obj_cache_eviction_number 5
# HELP api_gateway_obj_cache_hit_ratio Total obj cache hit ratio
# TYPE api_gateway_obj_cache_hit_ratio gauge
api_gateway_obj_cache_hit_ratio 0.6521739130434783
# HELP api_gateway_obj_cache_hit_total Total obj cache hit number
# TYPE api_gateway_obj_cache_hit_total counter
api_gateway_obj_cache_hit_total 15
# HELP api_gateway_obj_cache_miss_total Total obj cache miss number
# TYPE api_gateway_obj_cache_miss_total counter
api_gateway_obj_cache_miss_total 8
```
### dtable-db
Please refer to the [dtable-db docs](../../configuration/components/dtable-db.md#metrics) for instructions on how to enable metrics.
You can test the metrics endpoint by running the following command on the host:
```bash
docker exec seatable-server curl -sS http://localhost:7777/metrics --user ":"
```
**Note:** `curl` is executed inside the container since port 7777 is not exposed to the host by default.
Example Output
```text
# HELP dtable_db_archive_task_count Number of currently running import tasks
# TYPE dtable_db_archive_task_count gauge
dtable_db_archive_task_count 0
# HELP dtable_db_cache_base_count Number of currently cached bases
# TYPE dtable_db_cache_base_count gauge
dtable_db_cache_base_count 2
# HELP dtable_db_cache_memory The memory currently used by dtable cache
# TYPE dtable_db_cache_memory gauge
dtable_db_cache_memory 528760
# HELP dtable_db_in_flight_request_num The number of currently running http requests
# TYPE dtable_db_in_flight_request_num gauge
dtable_db_in_flight_request_num{method="GET",request="LIST ROWS"} 0
dtable_db_in_flight_request_num{method="POST",request="sql select"} 0
# HELP dtable_db_index_adding_count Number of currently running index adding
# TYPE dtable_db_index_adding_count gauge
dtable_db_index_adding_count 0
# HELP dtable_db_is_doing_backup Is dtable db doing backup now
# TYPE dtable_db_is_doing_backup gauge
dtable_db_is_doing_backup 0
# HELP dtable_db_is_doing_cleanup Is dtable db doing cleanup now
# TYPE dtable_db_is_doing_cleanup gauge
dtable_db_is_doing_cleanup 0
# HELP dtable_db_opened_bases Number of opened archived bases
# TYPE dtable_db_opened_bases gauge
dtable_db_opened_bases 1
# HELP dtable_db_opened_olap_bases Number of opened OLAP bases
# TYPE dtable_db_opened_olap_bases gauge
dtable_db_opened_olap_bases 0
# HELP dtable_db_request_duration_seconds Total request duration
# TYPE dtable_db_request_duration_seconds counter
dtable_db_request_duration_seconds{method="GET",request="LIST ROWS"} 0.07200000000000001
# HELP dtable_db_request_total Total http request count
# TYPE dtable_db_request_total counter
dtable_db_request_total{method="GET",request="LIST ROWS"} 3
# HELP dtable_db_unarchive_task_count Number of currently running unarchive tasks
# TYPE dtable_db_unarchive_task_count gauge
dtable_db_unarchive_task_count 0
```
### dtable-web
You can enable the `/metrics` endpoint and configure the basic auth credentials by adding the following variables inside `/opt/seatable-server/seatable/conf/dtable_web_settings.py`:
```python
ENABLE_METRIC = True
METRIC_AUTH_USER = ""
METRIC_AUTH_PWD = ""
```
Remember to restart SeaTable by running the following command:
```bash
docker restart seatable-server
```
You can test the metrics endpoint by running the following command on the host:
```bash
curl -sS https://$SEATABLE_SERVER_HOSTNAME/metrics --user ":"
```
Example Output
```text
# HELP realtime_automation_triggered_count The number of triggered realtime automations since start up
# TYPE realtime_automation_triggered_count gauge
realtime_automation_triggered_count{component="dtable_events",node="default"} 0
# HELP scheduled_automation_triggered_count The number of triggered scheduled automations since start up
# TYPE scheduled_automation_triggered_count gauge
scheduled_automation_triggered_count{component="dtable_events",node="default"} 0
# HELP automation_queue_size The number of automations in the queue
# TYPE automation_queue_size gauge
automation_queue_size{component="dtable_events",node="default"} 0
# HELP realtime_automation_heartbeat Heartbeat timestamp of realtime automations
# TYPE realtime_automation_heartbeat gauge
realtime_automation_heartbeat{component="dtable_events",node="default"} 1781268161.9465296
# HELP in_flight_request_total The number of currently running http requests.
# TYPE in_flight_request_total gauge
in_flight_request_total{component="go_fileserver",node="default"} 0
# HELP common_dataset_sync_count Common-dataset syncs count
# TYPE common_dataset_sync_count gauge
common_dataset_sync_count{component="dtable_events",node="default"} 0
# HELP common_dataset_sync_total_row_count Total rows processed in common-dataset syncs
# TYPE common_dataset_sync_total_row_count gauge
common_dataset_sync_total_row_count{component="dtable_events",node="default"} 0
# HELP common_dataset_sync_time_cost Time taken (in seconds) to complete common-dataset syncs job
# TYPE common_dataset_sync_time_cost gauge
common_dataset_sync_time_cost{component="dtable_events",node="default"} 0.01068
```
### Gunicorn
Gunicorn only supports the older **statsD** protocol to emit metrics.
[`statsd_exporter`](https://github.com/prometheus/statsd_exporter) can be used to ingest these metrics and transform them into Prometheus-compatible metrics.
You can enable this by adding the following configuration setting inside `/opt/seatable-server/seatable/conf/gunicorn.py`:
```py
statsd_host = 'statsd-exporter:9125'
```
Afterwards, Gunicorn must be restarted in order to apply the configuration changes:
```bash
docker restart seatable-server
```
You can use the following `statsd-exporter.yml` file to deploy the exporter alongside SeaTable:
```yaml
services:
statsd-exporter:
image: prom/statsd-exporter:v0.29.0
container_name: statsd-exporter
restart: unless-stopped
command: ["--statsd.mapping-config=/tmp/statsd-exporter-config.yml"]
networks:
- o11y-net
ports:
- 127.0.0.1:9102:9102
volumes:
- ./statsd-exporter-config.yml:/tmp/statsd-exporter-config.yml:ro
# Gunicorn needs to be able to access statsd-exporter
seatable-server:
networks:
- o11y-net
networks:
o11y-net:
name: o11y-net
```
This is the corresponding configuration file for the exporter (`statsd-exporter-config.yml`) that is mounted into the container:
```yaml
defaults:
observer_type: histogram
mappings:
- match: gunicorn.request.status.*
name: gunicorn_requests_total
labels:
status: $1
```
After adding `statsd-exporter.yml` to the `COMPOSE_FILE` variable and starting the container, the exporter will serve a metrics endpoint that contains metrics in a Prometheus-compatible format:
```bash
curl -sS 127.0.0.1:9102/metrics
```
Example Output
```text
# HELP gunicorn_request_duration Metric autogenerated by statsd_exporter.
# TYPE gunicorn_request_duration histogram
gunicorn_request_duration_bucket{le="0.005"} 7
gunicorn_request_duration_bucket{le="0.01"} 50
gunicorn_request_duration_bucket{le="0.025"} 142
gunicorn_request_duration_bucket{le="0.05"} 159
gunicorn_request_duration_bucket{le="0.1"} 163
gunicorn_request_duration_bucket{le="0.25"} 163
gunicorn_request_duration_bucket{le="0.5"} 164
gunicorn_request_duration_bucket{le="1"} 172
gunicorn_request_duration_bucket{le="2.5"} 173
gunicorn_request_duration_bucket{le="5"} 173
gunicorn_request_duration_bucket{le="10"} 173
gunicorn_request_duration_bucket{le="+Inf"} 173
gunicorn_request_duration_sum 10.003946999999993
gunicorn_request_duration_count 173
# HELP gunicorn_requests Metric autogenerated by statsd_exporter.
# TYPE gunicorn_requests counter
gunicorn_requests 173
# HELP gunicorn_requests_total Metric autogenerated by statsd_exporter.
# TYPE gunicorn_requests_total counter
gunicorn_requests_total{status="200"} 149
gunicorn_requests_total{status="302"} 24
# HELP gunicorn_workers Metric autogenerated by statsd_exporter.
# TYPE gunicorn_workers gauge
gunicorn_workers 5
```
### NGINX
In order to expose basic metrics regarding the number of connections and handled requests, the `ngx_http_stub_status_module` module must be enabled.
You can achieve this by adding the following configuration block at the bottom of the NGINX configuration file, which is located at `/opt/seatable-compose/config/seatable-config.conf`:
```nginx
server {
listen 8080;
location = /metrics {
stub_status;
}
}
```
Using a separate HTTP server ensures that the `/metrics` route won't be publicly accessible.
You can test the validity of your configuration file by running the following command:
```bash
docker exec -it seatable-server nginx -t
```
This should return the following output:
```text
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```
NGINX must be restarted in order to apply the configuration changes:
```bash
docker exec -it seatable-server sv restart nginx
```
[`nginx-prometheus-exporter`](https://github.com/nginx/nginx-prometheus-exporter) must be deployed alongside your SeaTable instance in order to expose these metrics in a Prometheus-compatible format.
You can use the following `nginx-exporter.yml` file to get started:
```yaml
services:
nginx-exporter:
image: nginx/nginx-prometheus-exporter:1.5.1
container_name: nginx-exporter
restart: unless-stopped
command: ["--nginx.scrape-uri=http://seatable-server:8080/metrics"]
networks:
- o11y-net
ports:
- 127.0.0.1:9113:9113
# nginx-exporter needs to access NGINX running inside seatable-server
seatable-server:
networks:
- o11y-net
networks:
o11y-net:
name: o11y-net
```
Remember to add `nginx-exporter.yml` to the `COMPOSE_FILE` variable and start the exporter by running the following command:
```bash
docker compose up -d
```
You can test the metrics endpoint by running the following command on the host:
```bash
curl -sS http://127.0.0.1:9113/metrics
```
Example Output
```text
# HELP nginx_connections_accepted Accepted client connections
# TYPE nginx_connections_accepted counter
nginx_connections_accepted 8
# HELP nginx_connections_active Active client connections
# TYPE nginx_connections_active gauge
nginx_connections_active 7
# HELP nginx_connections_handled Handled client connections
# TYPE nginx_connections_handled counter
nginx_connections_handled 8
# HELP nginx_connections_reading Connections where NGINX is reading the request header
# TYPE nginx_connections_reading gauge
nginx_connections_reading 0
# HELP nginx_connections_waiting Idle client connections
# TYPE nginx_connections_waiting gauge
nginx_connections_waiting 6
# HELP nginx_connections_writing Connections where NGINX is writing the response back to the client
# TYPE nginx_connections_writing gauge
nginx_connections_writing 1
# HELP nginx_exporter_build_info A metric with a constant '1' value labeled by version, revision, branch, goversion from which nginx_exporter was built, and the goos and goarch for the build.
# TYPE nginx_exporter_build_info gauge
nginx_exporter_build_info{branch="main",goarch="amd64",goos="linux",goversion="go1.25.3",revision="bae43bc818cd6e47a08163a7b31f355f454e9ecb",tags="unknown",version="0.0.0-SNAPSHOT-bae43bc"} 1
# HELP nginx_http_requests_total Total http requests
# TYPE nginx_http_requests_total counter
nginx_http_requests_total 153
# HELP nginx_up Status of the last metric scrape
# TYPE nginx_up gauge
nginx_up 1
```
### Redis
[`redis_exporter`](https://github.com/oliver006/redis_exporter) must be deployed alongside your Redis instance in order to expose the built-in Redis metrics in a Prometheus-compatible format.
You can use the following `redis-exporter.yml` file to get started:
```yaml
services:
redis-exporter:
image: oliver006/redis_exporter:v1.86.0
container_name: redis-exporter
restart: unless-stopped
environment:
- REDIS_ADDR=redis://redis:6379
- REDIS_PASSWORD=${REDIS_PASSWORD:?Variable is not set or empty}
networks:
- o11y-net
ports:
- 127.0.0.1:9121:9121
# redis-exporter needs to access Redis
redis:
networks:
- o11y-net
networks:
o11y-net:
name: o11y-net
```
Remember to add `redis-exporter.yml` to the `COMPOSE_FILE` variable and start the exporter by running the following command:
```bash
docker compose up -d
```
You can test the metrics endpoint by running the following command on the host:
```bash
curl -sS http://127.0.0.1:9121/metrics
```
Example Output
```text
# HELP redis_commands_total Total number of calls per command
# TYPE redis_commands_total counter
redis_commands_total{cmd="auth"} 85122
redis_commands_total{cmd="client|setinfo"} 290
redis_commands_total{cmd="client|setname"} 116
redis_commands_total{cmd="command"} 0
redis_commands_total{cmd="command|docs"} 1
redis_commands_total{cmd="config|get"} 115
redis_commands_total{cmd="del"} 495856
redis_commands_total{cmd="exec"} 31
redis_commands_total{cmd="exists"} 13771
redis_commands_total{cmd="expire"} 155
redis_commands_total{cmd="get"} 6.876658e+06
redis_commands_total{cmd="hello"} 127
redis_commands_total{cmd="incrby"} 4
redis_commands_total{cmd="info"} 124
```
### Caddy
[Caddy](https://caddyserver.com/) natively supports exposing metrics in a Prometheus-compatible format. Since SeaTable uses [caddy-docker-proxy](https://github.com/lucaslorentz/caddy-docker-proxy), metrics can be enabled by adding Docker labels to the Caddy service.
Create a `caddy-metrics.yml` file in your `/opt/seatable-compose` directory:
```yaml
services:
caddy:
labels:
caddy_0.metrics:
caddy_0.metrics.per_host:
caddy_1: ":2020"
caddy_1.metrics: /metrics
ports:
- 127.0.0.1:2020:2020
networks:
- o11y-net
networks:
o11y-net:
name: o11y-net
```
These labels configure Caddy to collect per-host metrics and expose them on a dedicated, read-only endpoint on port 2020 (separate from the Caddy Admin API on port 2019).
Add `caddy-metrics.yml` to the `COMPOSE_FILE` variable in your `.env` file and restart the containers:
```bash
docker compose up -d
```
You can test the metrics endpoint by running the following command on the host:
```bash
curl -sS http://127.0.0.1:2020/metrics
```
## Scraping
There are many ways to ingest the metrics into Prometheus.
### Grafana Alloy
You can use [Grafana Alloy](https://grafana.com/docs/alloy/latest/) to scrape metrics from SeaTable components and forward them to an existing [Prometheus server](https://prometheus.io/) using Prometheus' [remote-write](https://grafana.com/docs/alloy/latest/reference/components/prometheus/prometheus.remote_write/) functionality.
The following YAML manifest can serve as a starting point to deploy Alloy:
```yaml
services:
alloy:
image: grafana/alloy:v1.12.0
container_name: alloy
restart: unless-stopped
environment:
- PROMETHEUS_URL=${PROMETHEUS_URL:?Variable is not set or empty}
- PROMETHEUS_USERNAME=${PROMETHEUS_USERNAME:?Variable is not set or empty}
- PROMETHEUS_PASSWORD=${PROMETHEUS_PASSWORD:?Variable is not set or empty}
- SEATABLE_METRICS_USERNAME=${SEATABLE_METRICS_USERNAME:?Variable is not set or empty}
- SEATABLE_METRICS_PASSWORD=${SEATABLE_METRICS_PASSWORD:?Variable is not set or empty}
networks:
- o11y-net
volumes:
- ./config.alloy:/etc/alloy/config.alloy:ro
- /opt/alloy-data:/var/lib/alloy/data
command:
- run
- --server.http.listen-addr=0.0.0.0:12345
- --storage.path=/var/lib/alloy/data
- /etc/alloy/config.alloy
# Attach seatable-server container to o11y-net
# This allows Alloy to scrape metrics
seatable-server:
networks:
- o11y-net
networks:
o11y-net:
name: o11y-net
```
The following `config.alloy` config file should be created inside the same directory:
```alloy
prometheus.remote_write "default" {
endpoint {
url = env("PROMETHEUS_URL")
basic_auth {
username = env("PROMETHEUS_USERNAME")
password = env("PROMETHEUS_PASSWORD")
}
}
}
prometheus.scrape "seatable_metrics" {
targets = [
{"__address__" = "seatable-server:7780", "instance" = "api-gateway"},
{"__address__" = "seatable-server:7777", "instance" = "dtable-db"},
{"__address__" = "seatable-server:80", "instance" = "dtable-web"},
{"__address__" = "statsd-exporter:9102", "instance" = "gunicorn"},
{"__address__" = "nginx-exporter:9113", "instance" = "nginx"},
]
basic_auth {
username = env("SEATABLE_METRICS_USERNAME")
password = env("SEATABLE_METRICS_PASSWORD")
}
forward_to = [prometheus.remote_write.default.receiver]
scrape_interval = "15s"
}
// Caddy metrics do not use basic authentication and
// therefore require a separate scrape configuration.
prometheus.scrape "caddy_metrics" {
targets = [
{"__address__" = "caddy:2020", "instance" = "caddy"},
]
forward_to = [prometheus.remote_write.default.receiver]
scrape_interval = "15s"
}
```
## Grafana Dashboard
We have published a [Grafana dashboard](https://grafana.com/grafana/dashboards/24942-seatable-dashboard/) that displays these metrics.
You can import this dashboard into your Grafana instance by specifying its ID (`24942`).

---
Source: https://admin.seatable.com/installation/advanced/database-standalone/
# Standalone Database
Managed Database is an often used managed service. SeaTable can easily be configured to use a separate database. We recommend to initialize SeaTable with the default mariadb container. Then dump the database, load the dump to a separate database, update the `.env` file and restart SeaTable. Due to this assumption, this manual is the same for a new SeaTable Server or a service where you want to migrate the database.
## Stop SeaTable
```bash
docker stop seatable-server
```
Now you can be sure, that no more records are written or modified in the database.
## Dump and restore to another database
Please refer to [Backup and Recovery](../../maintenance/backup-recovery.md#mariadb-database) for instructions regarding the backup process for the MariaDB database.
You can use the `mariadb` CLI to import the contents of the dumped databases into the managed databases.
## Stop Mariadb
After the dump, stop also the database container:
```bash
docker stop mariadb
```
## Don't start mariadb container
To disable the `mariadb` service and patch the `depends_on` declaration for the `seatable-server` service, you should create a `custom-seatable-server.yml` file:
```yaml
services:
seatable-server:
# Patch depends_on to ensure that seatable-server can start up
# Note: The "!override" syntax requires at least Docker Compose v2.24.4
depends_on: !override
redis:
condition: service_healthy
mariadb:
profiles:
- never
```
Make sure to include this `custom-seatable-server.yml` in the `COMPOSE_FILE` variable in your `.env` file.
You can read our [guide] for more information on how this merging process of multiple configuration files works and the rationale behind it.
## Update environment variables
You should update/set the following environment variables in your `.env` file:
```ini
MARIADB_HOST=
MARIADB_PORT=
MARIADB_PASSWORD=
```
## Restart SeaTable
After that you can [restart SeaTable](../../maintenance/restart-seatable.md).
## Troubleshooting
Check the logs and look for any connection errors.
```bash
tail -f /opt/seatable-server/seatable/logs/*.log
```
## Remove old database
if everything is running good, you can delete the local database folder /opt/mariadb.
```bash
rm -r /opt/mariadb
```
---
Source: https://admin.seatable.com/installation/advanced/seafile/
# Integrate with Seafile
When integrating SeaTable and Seafile, users can add files from Seafile libraries in file columns.
### Scope of the Connection
The Seafile connection to SeaTable enables you to
- Choose a file as attachment from the Seafile library in SeaTable
- Save attachments in a SeaTable base to your Seafile library (WIP)
### How to Setup the Connection on SeaTable Server Side
- Go to Seafile and generate an API token for your library
- Go to SeaTable and click on the 3-dots menu inside a base, go to Third party integration > Seafile and enter the full URL (including “http” or “https”) and the API token and then submit.
### Requirements on the Seafile Server Side
The cross-domain permissions must be set. This can be done by adding the "Access-Control-Allow-Origin" header.
Add the following code block to the configuration file `seafile.conf` in `/etc/nginx/sites-available/` or `seafile.nginx.conf` in `/etc/nginx/sites-enabled` (the exact filename and path depend on your Seafile version and installation method):
```nginx
location / {
add_header Access-Control-Allow-Origin *;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
return 204;
}
proxy_pass http://127.0.0.1:8000;
...............
```
### Current Limitations
- Only a single library can be linked to a specific base
- The base editor does not display thumbnails for images stored inside an external Seafile library
- Image columns are not supported yet
---
## Cluster Deployment
Source: https://admin.seatable.com/installation/cluster/introduction/
# Introduction to the Cluster Setup
SeaTable can be operated both as a **single-node installation** and in **cluster mode**. The following section explains when each setup is appropriate and what advantages a cluster setup offers.
Originally (a long time ago), SeaTable was going to be called `dtable` (short for _database table_). Although this term was later replaced with *SeaTable*, many internal components and log entries still use the old name `dtable`. Whenever you see `dtable`, it simply refers to a component of SeaTable.
## Naming conventions
In the following instructions for deploying a SeaTable Cluster, I will use the node names and roles listed below as a naming convention. Please adapt these to fit your specific environment.
| Node | Main service / Name | Private IP address |
| ----- | ------------------- | ------------------ |
| node1 | dtable-web | 10.0.0.2 |
| node2 | dtable-db | 10.0.0.3 |
| node3 | dtable-server | 10.0.0.4 |
| node4 | dtable-server-2 | 10.0.0.5 |
| node5 | dtable-events | 10.0.0.6 |
## When is a single-node installation suitable?
In a single-node installation, all SeaTable components run on a single server. This setup is usually sufficient for small teams and organizations with up to several hundred users and offers good performance.
However, as the number of users and the complexity of the bases increase, bottlenecks may arise. In particular, the `dtable-server` - responsible for rendering the bases, see [the architecture of SeaTable for more details](../../introduction/architecture.md) - will eventually reach its performance limits. Depending on usage intensity and base size, this can occur with as few as 100 users, or only after surpassing 1.000 users.
**Typical signs of overload:**
- **Noticeably longer loading times** when opening a base.
- The appearance of so-called **kill events** in the `monitor.log`.
??? question "What is a Kill Event?"
SeaTable checks every 30 seconds whether its individual components are reachable. If a component does not respond within 20 seconds, the corresponding service is automatically stopped and restarted.
You will see such events in `logs/monitor.log`, for example:
```text
[2025-07-01 11:12:56] [WARNING] Ping error, kill dtable-server
```
The component name (e.g., `dtable-server`, `dtable-web`, `dtable-db`) indicates which service was affected.
Short-term improvements can often be achieved by allocating additional resources (CPU, RAM). However, in our experience, once you reach about **8 CPUs and 32 GB RAM**, further performance gains are negligible. If the `dtable-server` is overloaded by too many requests, even more resources cannot resolve the bottleneck, and kill events will occur.
??? question "What limits the dtable-server?"
The `dtable-server` is implemented in such a way that loading and saving the JSON files is a blocking process that cannot be parallelized further. This creates a bottleneck that limits scalability on a single server. See [the architecture of SeaTable for more details](../../introduction/architecture.md).
## When is a Cluster Setup Recommended?
Once the single-node setup reaches its performance limits, it is advisable to switch to a **cluster setup**. A cluster consists of multiple nodes, each running only selected components of the SeaTable server.
### Key features of a cluster setup
- All nodes use the same Docker image, but individual components are selectively enabled or disabled.
- The setup usually starts as a single-node installation. Gradually, individual components are moved to separate nodes.
- In the maximum expansion stage, each service runs on its own node; multiple `dtable-servers` and multiple `dtable-web` can run in parallel. Please note that the latter requires _sticky sessions_.

### Advantages of a cluster setup
- **Significantly more resources available:** Overall performance can be increased almost indefinitely by adding more nodes.
- **Targeted allocation of CPU and RAM:** Resources can be assigned to individual components as needed.
- **Higher performance:** Parallel operation of multiple dtable-servers allows many more users to be served simultaneously.
- **Improved fault tolerance:** If one node fails, other nodes can take over its tasks for highly available components like `dtable-web`. For components like `dtable-server`, only a portion of users may be affected if multiple instances are running.
While a cluster setup offers greater performance and availability, it also requires a solid understanding of distributed systems and experience in debugging. Operation is significantly more complex than with a single-node system. The following chapters will help you understand the requirements and setup of a SeaTable cluster.
Continue reading about the requirements and setup of a cluster [in the next article](./requirements.md).
---
Source: https://admin.seatable.com/installation/cluster/requirements/
# Requirements
The requirements for running a SeaTable cluster build upon those for a single-node setup. In addition to the standard prerequisites, the following requirements must be met to successfully deploy a cluster:
- **At least 4 nodes** (physical or virtual) each with a minimum of 2 CPUs and 4 GB RAM.
- All nodes are connected via a **private network**.
- One node (running dtable-web) must be publicly available via **port 80 and 443**.
- **S3-compatible object storage** is required for storing files and attachments. (Alternative storage technologies may be possible but are not covered in detail here.)
- **Centralized MariaDB and Redis services**: These must be accessible to all nodes in the private network. You can either use managed services or operate your own MariaDB and Redis instances.
- If you plan to use the **Office Editor**, the service should be deployed within the private network.
- You can deploy the **Python Pipeline** on the [same node as **dtable-web**](../components/python-pipeline.md) or on a [separate node](../advanced/python-pipeline-dedicated-server.md).
In our experience, configuring communication between nodes and the overall network setup is the trickiest part of a cluster deployment.
All nodes must be able to communicate with each other over a reliable, low-latency network connection.
The performance of services such as MariaDB, Redis, and object storage is critical for stable cluster operation.
If you can fulfill these requirements, you are ready to proceed with the [deployment of a SeaTable cluster](./basic-setup-with-external-services.md).
## Hardware recommendations for 1.000+ users
Organizations frequently ask about the hardware resources needed to support more than 1,000 users. The following setup is recommended for companies or teams with 1,000 users, assuming average usage patterns, including some heavy users, API usage, Python scripting, and automations.
This configuration is designed to handle typical workloads, but you should consider scaling resources further if you expect very large bases, intensive scripting, or high-frequency API calls, as these can significantly increase memory and CPU requirements.
| Server component | CPUs | RAM (in GB) | Local storage (in GB) |
| --- | --- | --- | --- |
| dtable-web | 4 | 16 | 100 |
| dtable-db | 4 | 16 | 100 |
| dtable-server | 4 | 8 | 50 |
| dtable-server-2 | 4 | 8 | 50 |
| dtable-server-3 | 4 | 8 | 50 |
| mariadb (self-hosted) | 4 | 16 | 100 |
| python pipeline | 2 | 4 | 50 |
---
## Step-by-step guide
Source: https://admin.seatable.com/installation/cluster/basic-setup-with-external-services/
# Basic Setup of a SeaTable Cluster
SeaTable currently does not support installing a cluster with a single command. This may change in the future, but for now, some configuration changes and migrations are required after deploying the Docker containers.
Every SeaTable Cluster installation starts with the deployment of a single node. The main difference is that, from the beginning, you use external services instead of running Redis and MariaDB on the same machine as SeaTable.
Afterwards we will move component after component to other nodes.

## Basic setup with external services
Follow the [installation instructions for a single node](../basic-setup.md) up to the point where you would start your SeaTable Server for the first time. Before starting the server, you need to make some additional changes to your setup.
??? success "Use external services instead of local MariaDB and Redis"
Update your `.env` file to include the required variables for `REDIS` and `MARIADB`. Set passwords, IPs, and usernames according to your environment. This ensures that your SeaTable Server connects to these external services.
```bash
# components to be used; IMPORTANT: there should be no space between
# the files names!
COMPOSE_FILE='caddy.yml,dtable-web.yml'
COMPOSE_PATH_SEPARATOR=','
# system settings
TIME_ZONE='Europe/Berlin'
# seatable server url
SEATABLE_SERVER_HOSTNAME='cluster.seatable.com
SEATABLE_SERVER_PROTOCOL='https'
# initial web admin
SEATABLE_ADMIN_EMAIL='cluster@seatable.com'
SEATABLE_ADMIN_PASSWORD='topsecret'
# database (managed service)
MARIADB_HOST=10.0.0.99
MARIADB_USER=root
MARIADB_PASSWORD='topsecret'
# redis (managed service)
REDIS_HOST=10.0.0.99
REDIS_PORT=6379
REDIS_PASSWORD='topsecret'
# shared secret for secure communication
JWT_PRIVATE_KEY='topsecret'
SECRET_KEY='anothertopsecret'
```
??? success "Remove Redis and Mariadb from your YAML file."
Create a copy of `seatable-server.yml` and name it, for example, `dtable-web.yml`. Make the following changes to this file:
- Remove the `depends_on:` entries for Redis and MariaDB.
- Remove the `backend-seatable-net` network, as it is no longer needed.
Example configuration:
```yaml
---
services:
seatable-server:
image: ${SEATABLE_IMAGE:-seatable/seatable-enterprise:x.x.x}
restart: unless-stopped
container_name: seatable-server
volumes:
...
environment:
...
labels:
...
networks:
- frontend-net
networks:
frontend-net:
name: frontend-net
```
Now, you can run `docker compose up -d` for the first time.
After starting, verify that only these two Docker containers are running on the SeaTable node:
- caddy
- seatable-server
Log in with your defined admin credentials for the first time to check, that the deployment was successful.
## Migration to S3 storage
Follow the instructions in the admin manual to [migrate from local storage to S3](../advanced/s3-migration.md) for the following data types:
- Base snapshots
- Files and pictures
- Avatars
Verify that everything is working by performing these steps:
- Create a new base. After a few minutes, you should see the `current` directory in the S3 bucket for storage.
- Create a new file/image column in the base and upload a file. You should see new entries in the S3 buckets for `fs`, `commits`, and `blocks`.
- Upload a new avatar. This should be stored in the S3 bucket for `avatars`.
Once you have verified that everything is working, you can continue with the deployment.
---
Source: https://admin.seatable.com/installation/cluster/dtable-db-standalone/
# dtable-db Standalone
To improve scalability and reliability, the next step is to move `dtable-db` to its own dedicated node.

## Setting Up a Standalone dtable-db Server
Prepare a new node with Docker installed, and copy the following files from your first node to this new node:
- `/opt/seatable-compose/.env`
- `/opt/seatable-compose/seatable-license.txt`
Open the `.env` file on the new node and ensure that the `COMPOSE_FILE` variable references only a single YAML file, like this:
```bash
COMPOSE_FILE='dtable-db.yml'
```
### Create `dtable-db.yml`
Now, create the `dtable-db.yml` file. You can either copy `dtable-web.yml` from the first node or use `seatable-server.yml` from the SeaTable release as a template.
Apply the following required changes to this file:
??? success "Remove all services except seatable-server"
The `dtable-db` node only requires the `seatable-server` service. Remove all other services (such as redis, mariadb, or caddy).
??? success "Remove all labels"
Since `dtable-db` node does not require Caddy or any TLS termination, remove all labels from the `seatable-server` service.
??? success "Add additional environment variables"
Add or update the following environment variables to ensure only `dtable-db` is enabled:
```yaml
environment:
#... all default environment variables in seatable-server.yml ...
# this node should only run dtable-db, all other services are disabled
- ENABLE_DTABLE_DB=true # that is, what we want
- ENABLE_DTABLE_STORAGE_SERVER=true # required for big data backup
- ENABLE_SEAFILE_SERVER=false
- ENABLE_DTABLE_WEB=false
- ENABLE_DTABLE_SERVER=false
- ENABLE_DTABLE_EVENTS=false
- ENABLE_API_GATEWAY=false
- SEATABLE_START_MODE=cluster # Don't run any database update processes
```
??? success "Expose port 7777"
The `dtable-db` node must be accessible to other nodes. Add the following to the `seatable-server` service:
```yaml
ports:
- 7777:7777
```
??? success "Configure internal network communication"
Node-to-node communication uses the internal network. Ensure all nodes can reach each other by adding their names and private IP addresses:
```yaml
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
```
For reference, here is an example of what your `dtable-db.yml` might look like (do not copy and paste directly — adapt as needed):
```yaml
---
services:
seatable-server:
image: ${SEATABLE_IMAGE:-seatable/seatable-enterprise:x.x.x}
restart: unless-stopped
container_name: seatable-server
volumes:
- "/opt/seatable-server:/shared"
- type: bind
source: "./seatable-license.txt"
target: "/shared/seatable/seatable-license.txt"
read_only: ${SEATABLE_LICENSE_FORCE_READ_ONLY:-false}
environment:
...
...
# this node should only run dtable-db
- ENABLE_DTABLE_DB=true
- ENABLE_DTABLE_STORAGE_SERVER=true
- ENABLE_SEAFILE_SERVER=false
- ENABLE_DTABLE_WEB=false
- ENABLE_DTABLE_SERVER=false
- ENABLE_DTABLE_EVENTS=false
- ENABLE_API_GATEWAY=false
- SEATABLE_START_MODE=cluster
ports:
- 7777:7777
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
networks:
- frontend-net
networks:
frontend-net:
name: frontend-net
```
Now, start dtable-db for the first time and monitor the logs:
```bash
docker compose up -d
```
## Changes after first start
After the first start of `dtable-db` you need to make the following changes to newly created configuration files:
??? success "Add S3 configuration"
Add the S3 configuration to `conf/dtable-storage-server.conf` - analog to your first node.
??? success "Two additional configuration changes"
Open `conf/dtable-db.conf` and make these two changes:
- set `host` to 0.0.0.0 that other nodes can reach dtable-db.
- add `[dtable cache]` to tell `dtable-db` where to find `dtable-server`.
```ini
[general]
host = 0.0.0.0
[dtable cache]
dtable_server_url = "http://dtable-web:5000"
```
### Verify installation on dtable-db
Now it is time to restart dtable-db and verify that the service is running and port 7777 is exposed. Simply run:
```bash
curl 127.0.0.1:7777/ping/
```
You should receive the following response:
```json
{"ret":"pong"}
```
## Configure dtable-web to use the standalone dtable-db
Now that dtable-db is up and running, it is time to tell dtable-web to use this separate node instead of the internal component.
These are the changes, you have to do.
??? success "Disable dtable-db in `.env`"
Open `/opt/seatable-compose/dtable-web.yml` and make these changes:
```yaml
environment:
- ENABLE_DTABLE_DB=false
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
ports:
- "5000:5000"
```
??? success "Create configuration file for the API-Gateway"
Create a new configuration file `conf/dtable-api-gateway.conf` and add these lines to tell this node, where to find `dtable-db`
```ini
[dtable-db]
server_address = "http://dtable-db:7777"
```
??? success "Update `dtable_web_settings.py`"
Open the configuration file `/conf/dtable_web_settings.py` and add this line:
```python
INNER_DTABLE_DB_URL = 'http://dtable-db:7777/'
```
??? success "Update `dtable_server_config.json`"
Open the configuration file `conf/dtable_server_config.json` and add this line. Make sure, that it is valid json, meaning the last key-value pair, does not have a comma at the end.
```json
"dtable_db_service_url": "http://dtable-db:7777"
```
### Restart dtable-web server
```sh
docker compose up -d
```
## Verify complete setup
A good way to verify, that the two nodes are working fine, is to open a universal app in the webinterface. You should see log entries on `dtable-db` in `/logs/dtable-db-access.log`.
Congratulations. dtable-db is now standalone.
---
Source: https://admin.seatable.com/installation/cluster/dtable-server-standalone/
# Installation dtable-server as a standalone node
The next step in building your SeaTable cluster is to move the `dtable-server` to a separate node.

## Setting up a standalone dtable-server
Prepare a new node with Docker installed, and copy the following files from one of your existing nodes to the new node:
- `/opt/seatable-compose/.env`
- `/opt/seatable-compose/seatable-license.txt`
Edit the `.env` file on the new node and ensure the `COMPOSE_FILE` variable references only a single YAML file:
```bash
COMPOSE_FILE='seatable-server-standalone.yml'
```
Copy `seatable-server.yml` to `seatable-server-standalone.yml` and make the following changes to configure it as a standalone `dtable-server`.
### Required changes to `seatable-server-standalone.yml`
Apply the following required changes to this file:
??? success "Remove all services except seatable-server"
The standalone node only requires the `seatable-server` service. Remove all other services (such as redis, mariadb, or caddy).
??? success "Add additional environment variables"
Add or update the following environment variables to ensure only the `dtable-server` is enabled:
```yaml
environment:
#... all default environment variables in seatable-server.yml ...
# this node should only run dtable-server, all other services are disabled
- ENABLE_DTABLE_DB=false
- ENABLE_DTABLE_STORAGE_SERVER=true
- ENABLE_SEAFILE_SERVER=false
- ENABLE_DTABLE_WEB=false
- ENABLE_DTABLE_SERVER=true
- ENABLE_DTABLE_EVENTS=false
- ENABLE_API_GATEWAY=false
- SEATABLE_START_MODE=cluster
```
??? success "Expose port 5000"
The `dtable-server` node must be accessible to other nodes. Add the following to the `seatable-server` service:
```yaml
ports:
- 5000:5000
```
??? success "Configure internal network communication"
Node-to-node communication uses the internal network. Ensure all nodes can reach each other by adding their names and private IP addresses:
```yaml
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
```
### Example: `dtable-server-standalone.yml`
For reference, here is an example of what your `dtable-server-standalone.yml` might look like. Do not copy and paste directly — adapt to your environment as needed.
```yaml
---
services:
seatable-server:
image: ${SEATABLE_IMAGE:-seatable/seatable-enterprise:x.x.x}
restart: unless-stopped
container_name: seatable-server
volumes:
- "/opt/seatable-server:/shared"
- type: bind
source: "./seatable-license.txt"
target: "/shared/seatable/seatable-license.txt"
read_only: ${SEATABLE_LICENSE_FORCE_READ_ONLY:-false}
environment:
...
...
# this node should only run dtable-server
- ENABLE_DTABLE_DB=false
- ENABLE_DTABLE_STORAGE_SERVER=true
- ENABLE_SEAFILE_SERVER=false
- ENABLE_DTABLE_WEB=false
- ENABLE_DTABLE_SERVER=true
- ENABLE_DTABLE_EVENTS=false
- ENABLE_API_GATEWAY=false
- SEATABLE_START_MODE=cluster
ports:
- 5000:5000
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
networks:
- frontend-net
networks:
frontend-net:
name: frontend-net
```
Now, start `dtable-server` for the first time and monitor the logs:
```bash
docker compose up -d
```
## Changes after first start
After the first start of `dtable-server`, make the following changes to the newly created configuration files:
??? success "Add S3 configuration"
Add the S3 configuration to `conf/dtable-storage-server.conf`, analogous to your first or second node.
??? success "Additional configuration changes"
Open `conf/dtable_server_config.json` and add these entries:
```json
{
"dtable_db_service_url": "http://dtable-db:7777",
"dtable_web_service_url": "http://dtable-web:8000"
}
```
Now it is time to restart dtable-server and verify that the service is running, port 5000 is exposed and a `pong` is returned:
```bash
curl 127.0.0.1:5000/ping/
```
## Configure dtable-web to use the standalone dtable-server
Now that `dtable-server` is running on a separate node, update `dtable-web` to use this node instead of the internal component.
??? success "Disable dtable-server in dtable-web"
Open `/opt/seatable-compose/dtable-web.yml` and make these changes:
```yaml
environment:
- ENABLE_DTABLE_SERVER=false
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
ports:
- "8000:8000"
```
??? success "Update API-Gateway"
Open the configuration file `conf/dtable-api-gateway.conf` and add these lines to specify the location of `dtable-server`:
```ini
[dtable-server]
server_address = "http://dtable-server:5000"
```
??? success "Update `dtable_web_settings.py`"
Open `/conf/dtable_web_settings.py` and add:
```python
INNER_DTABLE_SERVER_URL = 'http://dtable-server:5000/'
```
## Additional changes on dtable-db
Specify the location of `dtable-server` in `dtable-db` as well.
??? success "Update `dtable-db.conf`"
Find the relevant section and update the value:
```ini
[dtable cache]
dtable_server_url = "http://dtable-server:5000"
```
## Restart SeaTable on all three nodes
```sh
docker compose up -d
```
## Verify complete setup
Open any base in your web browser and check that logs are being created on the `dtable-server` node.
Congratulations! You are now running a separate `dtable-server` and have completed the next step in building your SeaTable cluster.
---
Source: https://admin.seatable.com/installation/cluster/dtable-server-multiple/
# Installation multiple dtable-servers
As your system grows, the `dtable-server` often becomes the first bottleneck. To address this, you can **scale dtable-server horizontally**. This guide explains how to set up multiple dtable-servers and configure a proxy on the `dtable-web` node to distribute base requests between them.

## Routing logic with multiple dtable-servers
Proper routing logic is essential when running multiple dtable-servers. While `seatable-server` itself is stateless, it is **crucial that all users open a specific base on the same dtable-server**.
- When a base is opened, dtable-server loads it into memory and only writes updates to disk every five minutes.
- If the same base is opened on two different dtable-servers, their changes can overwrite each other — this must be avoided.
To ensure consistency, implement a **fixed mapping of bases to dtable-servers** using the `base_uuid`. This ensures each base is always handled by the same server. This setup is not a failover solution, but it scales horizontally and can support thousands or even tens of thousands of users.
**Example mapping logic:**
- Bases starting with `0-9`: handled by the first dtable-server.
- Bases starting with `a-f`: handled by the second dtable-server.
## Setting up a second dtable-server
1. **Install a second dtable-server** as described in the [dtable-server (standalone)](dtable-server-standalone.md) section. Name it `dtable-server-2`.
2. **Update the private network configuration**: Add the IP address of the new server to the `extra_hosts` section on all nodes.
```yaml
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
- "dtable-server-2:10.0.0.5
```
3. **Verify** that `dtable-server-2` is accessible on port 5000.
## Adding a Proxy to Distribute Requests
To route requests to the correct `dtable-server`, add a **proxy component** (using either NGINX or Caddy), called `dtable-server-proxy`. Deploy this on the `dtable-web` node.
### Create the Proxy Service
Create `/opt/seatable-compose/dtable-server-proxy.yml` on `dtable-web`:
=== "NGINX"
```yaml
services:
dtable-server-proxy:
image: nginx:1.27.5-alpine
container_name: dtable-server-proxy
restart: unless-stopped
ports:
- "5000:5000"
volumes:
- ./nginx-proxy.conf:/etc/nginx/nginx.conf:ro
networks:
- frontend-net
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
- "dtable-server-2:10.0.0.5"
logging:
driver: json-file
options:
# Maximum size per file
max-size: 10m
# Maximum number of files
max-file: 3
networks:
frontend-net:
name: frontend-net
```
=== "Caddy"
```yaml
services:
dtable-server-proxy:
image: caddy:2.11.2-alpine
container_name: dtable-server-proxy
restart: unless-stopped
ports:
- 5000:5000
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
networks:
- backend-seatable-net
healthcheck:
test: ["CMD-SHELL", "curl --fail http://localhost:2019/metrics || exit 1"]
start_period: 20s
interval: 20s
timeout: 5s
retries: 3
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
- "dtable-server-2:10.0.0.5"
logging:
driver: json-file
options:
max-size: 10m
max-file: 3
```
### Configure Routing
=== "NGINX"
Create `/opt/seatable-compose/nginx-proxy.conf` on `dtable-web`.
This configuration defines two upstream servers and a routing map:
```nginx
worker_processes auto;
events {
worker_connections 4096;
}
http {
access_log off;
error_log /dev/stdout warn;
# dtable-server 1
upstream dtable_server_a_z {
server dtable-server:5000;
keepalive 15;
}
# dtable-server 2
upstream dtable_server_0_9 {
server dtable-server-2:5000;
keepalive 15;
}
# Map to dynamically determine the upstream server based on the UUID in the URL
map $request_uri $dtable_upstream {
default dtable_server_a_z; # Default to the a-z server
"~*ff84e1a1-66e2" dtable_server_0_9; # force this base to server 2
"~*([a-zA-Z])([0-9a-f]{7}-[0-9a-f]{4})" dtable_server_a_z;
"~*([0-9])([0-9a-f]{7}-[0-9a-f]{4})" dtable_server_0_9;
}
server {
server_name _;
listen 5000;
location / {
proxy_pass http://$dtable_upstream;
proxy_set_header X-Upstream-Server $dtable_upstream;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
access_log /tmp/access.log;
error_log /tmp/error.log;
}
}
}
```
You can adapt the routing logic as needed, for example by splitting bases differently or forcing specific `base_uuid`s to a particular server.
=== "Caddy"
Create `/opt/seatable-compose/Caddyfile` on `dtable-web`:
```Caddyfile
{
# Enable metrics
metrics
}
:5000 {
# Use route to disable internal reordering of directives
route {
metrics /metrics
# Static paths are proxied to dtable-server:5000
@staticPaths {
path /api/v1/admin/sys-info/
}
reverse_proxy @staticPaths dtable-server:5000
request_body {
max_size 100MB
}
# We cannot use Caddy's path_regexp matcher since this does not check query parameters
# However, clients connect to dtable-server using /socket.io?dtable_uuid= so
# we rely on Caddy's CEL (Common Expression Language) instead to match against the full URI
@dtable_09 `{http.request.orig_uri}.matches('[0-9][0-9a-f]{7}-[0-9a-f]{4}')`
@dtable_az `{http.request.orig_uri}.matches('[a-zA-Z][0-9a-f]{7}-[0-9a-f]{4}')`
reverse_proxy @dtable_az dtable-server:5000
reverse_proxy @dtable_09 dtable-server-2:5000
# Respond with 404 if nothing matches
respond 404
}
}
```
## Required Configuration Changes
??? success "Start dtable-server-proxy"
Add `dtable-server-proxy.yml` to your `.env` by including it in the `COMPOSE_FILE` variable. This ensures the proxy container starts.
??? success "Allow direct access to dtable-web"
Edit `conf/gunicorn.py` and update the bind address:
```python
bind = '0.0.0.0:8000'
```
??? success "Update INNER_DTABLE_SERVER"
Edit `conf/dtable_web_settings.py` and set:
```python
INNER_DTABLE_SERVER = 'http://dtable-web:5000/'
```
??? success "Update Ping endpoints"
Edit `/opt/seatable-compose/config/seatable-nginx.conf` to update ping endpoints:
```bash
# ping endpoints
location = /dtable-server/ping/ {
proxy_pass http://dtable-web:5000/ping/;
}
location = /dtable-db/ping/ {
proxy_pass http://dtable-db:7777/ping/;
}
```
Restart all containers on `dtable-web` to apply the changes.
### Updates on dtable-db
Since the routing logic has changed, update `dtable-db` so it always uses the proxy instead of contacting `dtable-server` directly.
??? success "Use dtable-server-proxy on dtable-db"
Edit `conf/dtable-db` and set:
```ini
[dtable cache]
dtable_server_url = "http://dtable-web:5000"
```
### Unload all bases on dtable-servers
To ensure no bases remain in memory on the dtable-servers, **restart both servers**. This prevents issues with parallel saving of bases.
Any time you modify the proxy logic in your nginx/Caddy configuration, you must restart all dtable-servers. Since `dtable-server` can keep bases in memory for up to 24 hours, failing to restart may result in data loss or inconsistencies.
## Verify your setup
Use the following tests to confirm your configuration:
| Where to execute | Test | Expected result |
| --- | --- | --- |
| dtable-web | `curl http://127.0.0.1:5000/ping/` | pong |
| dtable-web | `curl http://127.0.0.1:8000/api2/ping/` | pong |
| Browser | Open a base with `base_uuid` starting a-z | Log entries on `dtable-server` |
| Browser | Open a base with `base_uuid` starting 0-9 | Log entries on `dtable-server-2` |
| Browser | Open a universal app | Log entries on `dtable-db` |
## Final thoughts
Congratulations! Your setup now uses two dtable-servers, laying the foundation for even greater scalability. To add additional dtable-servers, repeat these steps:
- Set up another dtable-server.
- Add the new upstream to `nginx.conf` or `Caddyfile` (dtable-server-proxy).
- Restart all dtable-servers to clear their memory.
---
Source: https://admin.seatable.com/installation/cluster/dtable-events-background-node/
# dtable-events background Node
`dtable-events` is the workhorse of SeaTable Server, handling resource-intensive tasks such as syncing common datasets, PDF generation, scheduled automations, and more.
If your system is heavily loaded with these tasks, it may be beneficial to **separate dtable-events onto its own node**. This step is only necessary if you observe resource constraints on `dtable-web`.
There are two types of tasks performed by dtable-events:
- **Foreground tasks** (instant): Must be executed immediately.
- **Background tasks**: Not time-critical and can be processed asynchronously.
**Examples:**
| Type | Task |
|--------------|--------------------------------------|
| foreground | Import/Export of a base or view |
| foreground | PDF generation |
| background | Common dataset sync |
| background | Sending notifications or emails |
| background | Database cleanup |
| background | Scheduled automations |
SeaTable allows you to **split dtable-events**, moving background tasks to a dedicated node while foreground tasks continue to run alongside `dtable-web`.
## Setting up the dtable-events background Node
1. **Prepare a new node** with Docker installed.
2. **Copy the following files** from your first node to the new node:
- `/opt/seatable-compose/.env`
- `/opt/seatable-compose/seatable-license.txt`
- `/opt/seatable-server/seatable/conf/dtable_web_settings.py`
This is mandatory since **dtable-events** reads some configuration settings from `dtable_web_settings.py`.
3. **Edit the `.env` file** on the new node and set the `COMPOSE_FILE` variable to reference only a single YAML file:
```bash
COMPOSE_FILE='dtable-events.yml'
```
### Create `dtable-events.yml`
You can either copy `dtable-web.yml` from the first node or use `seatable-server.yml` from the SeaTable release as a template.
Apply the following required changes:
??? success "Remove all services except seatable-server"
The `dtable-events` node only requires the `seatable-server` service. Remove all other services (such as redis, mariadb, or caddy).
??? success "Remove all labels"
Since `dtable-events` node does not require Caddy or any TLS termination, remove all labels from the `seatable-server` service.
??? success "Add additional environment variables"
Add or update the following environment variables to ensure only `dtable-event` is enabled:
```yaml
environment:
# necessary for dtable-events (background)
- ENABLE_DTABLE_EVENTS=true
- DTABLE_EVENTS_TASK_MODE=background
- ENABLE_DTABLE_STORAGE_SERVER=true
- ENABLE_SEAFILE_SERVER=true
# should be disabled
- ENABLE_DTABLE_DB=false
- ENABLE_DTABLE_WEB=false
- ENABLE_DTABLE_SERVER=false
- ENABLE_API_GATEWAY=false
- SEATABLE_START_MODE=cluster
```
??? success "Configure internal network communication"
Ensure all nodes can reach each other by adding their names and private IP addresses:
```yaml
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
- "dtable-server-2:10.0.0.5"
- "dtable-events:10.0.0.6"
```
### Example `dtable-events.yml`
*Do not copy and paste directly — adapt as needed:*
```yaml
---
services:
seatable-server:
image: ${SEATABLE_IMAGE:-seatable/seatable-enterprise:x.x.x}
restart: unless-stopped
container_name: seatable-server
volumes:
- "/opt/seatable-server:/shared"
- type: bind
source: "./seatable-license.txt"
target: "/shared/seatable/seatable-license.txt"
read_only: ${SEATABLE_LICENSE_FORCE_READ_ONLY:-false}
environment:
...
- ENABLE_DTABLE_EVENTS=true
- DTABLE_EVENTS_TASK_MODE=background
- ENABLE_DTABLE_STORAGE_SERVER=true
- ENABLE_SEAFILE_SERVER=true
- ENABLE_DTABLE_DB=false
- ENABLE_DTABLE_WEB=false
- ENABLE_DTABLE_SERVER=false
- ENABLE_API_GATEWAY=false
- SEATABLE_START_MODE=cluster
extra_hosts:
- "dtable-web:10.0.0.2"
- "dtable-db:10.0.0.3"
- "dtable-server:10.0.0.4"
- "dtable-server-2:10.0.0.5"
- "dtable-events:10.0.0.6"
networks:
- frontend-net
networks:
frontend-net:
name: frontend-net
```
Start `dtable-events` for the first time and monitor the logs:
```bash
docker compose up -d
```
??? example "Why are no ports exposed?"
`dtable-events` does not need to expose any ports. It runs internal cron jobs and subscribes to Redis channels. No direct external connection is required.
## Changes after first start
After starting `dtable-events` for the first time, update the configuration files as follows:
??? success "Add S3 configuration"
Add the S3 configuration to both `conf/dtable-storage-server.conf` and `conf/seafile.conf` — just as you did on your first node.
Restart the container to apply these changes.
## Final changes on dtable-web
Now that background tasks are handled by the new node, you should disable them on `dtable-web`.
Open `/opt/seatable-compose/dtable-web.yml` and add the following to the environment variables:
```bash
DTABLE_EVENTS_TASK_MODE=foreground
```
Restart `dtable-web` to apply the changes.
---
Your `dtable-events` background node is now set up, and resource-intensive background tasks are offloaded from your main web node. This improves performance and scalability for large SeaTable installations.
---
## Cluster Deployment
Source: https://admin.seatable.com/installation/cluster/managed-services/
# Managed services
```bash
# components to be used; IMPORTANT: there should be no space between the files names !
COMPOSE_FILE='mariadb.yml,redis.yml,s3.yml'
COMPOSE_PATH_SEPARATOR=','
# system settings
TIME_ZONE='Europe/Berlin'
# database
MARIADB_PASSWORD='xxx'
REDIS_PASSWORD='xxx'
```
## S3 with minio
```yaml
---
services:
caddy:
image: ${CADDY_IMAGE:-lucaslorentz/caddy-docker-proxy:2.8.11-alpine}
restart: unless-stopped
container_name: caddy
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=frontend-net
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "/opt/caddy:/data/caddy"
networks:
- frontend-net
healthcheck:
test: ["CMD-SHELL", "curl --fail http://localhost:2019/metrics || exit 1"]
start_period: 20s
interval: 20s
timeout: 5s
retries: 3
minio:
container_name: minio
image: minio/minio:RELEASE.2024-12-18T13-15-44Z
networks:
- frontend-net
volumes:
- '/opt/minio_data:/data'
environment:
- MINIO_ROOT_USER=minio
- MINIO_ROOT_PASSWORD=s3_topsecret
- MINIO_SERVER_URL=https://
- MINIO_BROWSER_REDIRECT_URL=https:///console
command: server /data --console-address ":9090"
labels:
caddy:
caddy.redir: /console /console/
caddy.reverse_proxy: "{{upstreams 9000}}"
caddy.handle_path: /console/*
caddy.handle_path.0_reverse_proxy: "{{upstreams 9090}}"
networks:
frontend-net:
name: frontend-net
```
## Redis
```yaml
---
services:
redis:
image: ${SEATABLE_REDIS_IMAGE:-redis:7.2.7-bookworm}
restart: unless-stopped
container_name: redis
environment:
- REDIS_PASSWORD=${REDIS_PASSWORD:?Variable is not set or empty}
command:
- /bin/sh
- -c
- redis-server --requirepass "$${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"
networks:
- backend-seatable-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 20s
retries: 3
timeout: 5s
ports:
- 6379:6379
networks:
backend-seatable-net:
name: backend-seatable-net
```
## Mariadb
```yaml
---
services:
mariadb:
image: ${SEATABLE_DB_IMAGE:-mariadb:11.4.3-noble}
restart: unless-stopped
container_name: mariadb
environment:
- MYSQL_ROOT_PASSWORD=${SEATABLE_MYSQL_ROOT_PASSWORD:?Variable is not set or empty}
- MYSQL_LOG_CONSOLE=true
- MARIADB_AUTO_UPGRADE=1
- TZ=Europe/Berlin
volumes:
- "/opt/mariadb:/var/lib/mysql"
networks:
- backend-seatable-net
healthcheck:
test:
[
"CMD",
"/usr/local/bin/healthcheck.sh",
"--connect",
"--mariadbupgrade",
"--innodb_initialized",
]
interval: 20s
retries: 3
start_period: 30s
timeout: 10s
ports:
- 3306:3306
networks:
backend-seatable-net:
name: backend-seatable-net
```
---
## Configuration
Source: https://admin.seatable.com/configuration/plugins/
# Plugins
SeaTable Server supports plugins. Plugins provide additional visualization or interaction possibilities within a SeaTable base. Examples of SeaTable plugins include the Gallery, the Map or the Kanban board, providing users with versatile options to visualize their data.
Discover a comprehensive list of publicly available plugins and learn how to leverage them in our [user documentation](https://seatable.com/help/plugins-overview).
Typically, installation of a plugin requires action from the system administrator on the SeaTable server. Once installed, any user can easily activate the plugin within their base, unlocking its full potential.
## Activation / Update of plugins
System administrators have three distinct methods to install plugins into your SeaTable server. Users or team admins do not have the capability to install plugins.
### Option 1: Installation/Update via Web Interface
Navigate to the system administration area and select **Plugins** from the left navigation bar. Click on **Import plugin from market** and choose the desired plugin. Please ensure that your SeaTable Server has internet access and can download zip files from .

After a few moments, the plugin will appear in the list of installed plugins. Subsequently, all users can activate the plugins in any base.
In the event that a new version becomes available, a button will appear on the plugin card. Simply click on this button to initiate the update process for the plugin.

### Option 2: Upload via ZIP-File
If your server lacks internet connectivity, you can still install Plugins by downloading them as ZIP files to your local PC and subsequently uploading them to the SeaTable Server.
The complete plugin archive can be found at the following URL: .

After a brief moment, the plugin will appear in the list of installed plugins, allowing all users to activate it in any base.
To update a plugin, simply upload the latest version as a zip file. SeaTable will automatically detect the newer version and update the plugin accordingly.
### Option 3: Plugins via API
SeaTable Server offers API endpoints for installing and updating plugins. For further details, please refer to the API reference documentation.
-
-
## Configuration of the plugins
Typically, plugins do not necessitate additional configuration. However, there are two exceptions:
- the Map plugin, which presently relies on the Google Maps API and requires two API keys.
- the Whiteboard Plugin (tldraw), which requires a separate Docker container.
### Map Plugin
The Map plugin works exclusively with the Google Maps Platform. To enable it, you need two Google API keys, each with different permissions:
- Geocoding API
- Maps Javascript API
The "Map" page type inside universal apps, which was introduced in SeaTable v6.1, will only be visible once you've configured the variable `DTABLE_GOOGLE_MAP_KEY`.
Using two separate keys is recommended for security and cost control. While technically the same key could be used for both, separating them ensures that your Geocoding API key (which is expensive) is not exposed to end users.
```bash
DTABLE_GOOGLE_MAP_KEY = ''
SERVER_GOOGLE_MAP_KEY = ''
```

To safeguard your Google API Keys from abuse, restrict their usage. However, even with restrictions in place, abuse remains a risk—especially since `DTABLE_GOOGLE_MAP_KEY` must be included in your source code and is therefore publicly accessible.
Additionally, heavy use of the maps plugin may increase your Google billing, so **monitor your spending closely**.
| Key | Application restriction | API restriction |
| --- | --- | --- |
| `DTABLE_GOOGLE_MAP_KEY` | Restrict to your Server URL, like `https://cloud.seatable.io` | Maps Javascript API |
| `SERVER_GOOGLE_MAP_KEY` | **No website restriction** | Geocoding API |
#### `SERVER_GOOGLE_MAP_KEY`
- Used for **server-side requests** (Geocoding API).
- **Do not** restrict it to a website (since requests originate from the server).
- Restrict it instead by **API usage** → only allow the *Geocoding API*.

#### `DTABLE_GOOGLE_MAP_KEY`
- Used for **client-side requests** (Maps JavaScript API).
- This key must be embedded in the frontend and will therefore be **publicly visible**.
- Restrict it to your **SeaTable server’s domain** (HTTP referrers).
- Allow usage only for the *Maps JavaScript API*.

Remember to [restart the SeaTable Service](../maintenance/restart-seatable.md) to apply the changes from the updated configuration file.
### Whiteboard Plugin
Please follow this [instruction to install the tldraw container](../installation/components/whiteboard.md) on the same host where the SeaTable Server is running.
---
Source: https://admin.seatable.com/configuration/sending-email/
# Sending Email Notifications on SeaTable
SeaTable requires an external SMTP account to send emails. There are currently five types of emails that SeaTable sends:
- User resets their password
- User has been added as a collaborator in a table, or mentioned in a comment (depends on the user's email notification settings and that the notification is not seen within 1 hour)
- User has been shared with a base or added to a group
- System admin adds new members
- System admin resets user password
## Configuration
There are two ways to configure this SMTP account for system wide emails.
=== "Environment variables"
The SeaTable Server image supports auto configuration via environment variables.
This is the **preferred approach**.
Add these variables to your .env file to configure the SMTP account:
| Environment variable | Description | Example values |
| ------------------------------ | -------------------------------------------------------------- | ------------------------------ |
| `SEATABLE_EMAIL_USE_TLS` | Activate/Deactivate TLS/SSL encryption | `true` or leave empty. |
| `SEATABLE_EMAIL_USE_SSL` | Activate/Deactivate SSL encryption (only available as of v6.1) | `true` or leave empty. |
| `SEATABLE_EMAIL_HOST` | URL or IP address or the SMTP server | `mail.gmx.net` |
| `SEATABLE_EMAIL_HOST_USER` | Username for authentication | `seatable@gmx.de` |
| `SEATABLE_EMAIL_HOST_PASSWORD` | Password for authentication | `topsecret` |
| `SEATABLE_EMAIL_PORT` | Port that should be used | Typically `25`, `587` or `465` |
| `SEATABLE_DEFAULT_FROM_EMAIL` | Used for `From:` | `seatable@gmx.de` |
| `SEATABLE_SERVER_EMAIL` | Used for `From:` in case of error reporting | `seatable@gmx.de` |
See the examples at the end of this article for easy copy-and-paste use.
=== "Configuration file (deprecated)"
!!! warning "Configuration via `dtable_web_settings.py` is deprecated"
The configuration of email settings via `dtable_web_settings.py` is deprecated since v6.2.
Please migrate to the environment variable-based configuration approach when **upgrading to v6.2**.
Add the following lines to `dtable_web_settings.py` to enable email sending.
```python
EMAIL_USE_TLS = False # Either True or False
EMAIL_HOST = 'smtp.example.com' # Hostname of your SMTP server
EMAIL_HOST_USER = 'username@example.com' # Username for authentication
EMAIL_HOST_PASSWORD = 'password' # Password
EMAIL_PORT = 25
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USER
```
If you want to use the email service without authentication, leave `EMAIL_HOST_USER` and `EMAIL_HOST_PASSWORD` **blank** (`''`).
Restart SeaTable service to reload the changes.
## Debugging
If your email service does not work, check the log file `logs/dtable_web.log` to see what may have caused the problem.
Otherwise use a command line tool like [Swaks](https://github.com/jetmore/swaks) to debug your smtp settings.
```bash
# example of a swaks command to verify your settings
# (use -tls for TLS and -tlsc for SSL)
swaks --auth -tls \
--server \
--protocol SMTP \
--port \
--au \
--ap \
--from \
--to \
--h-Subject: "Subject of the mail" \
--body 'Test email!'
```
## Examples
### Gmail
If you are using Gmail as email server, you can use the following settings.
=== "Environment variables"
```python
SEATABLE_EMAIL_USE_TLS = True
SEATABLE_EMAIL_HOST = 'smtp.gmail.com'
SEATABLE_EMAIL_HOST_USER = 'username@gmail.com'
SEATABLE_EMAIL_HOST_PASSWORD = 'password'
SEATABLE_EMAIL_PORT = 587
SEATABLE_DEFAULT_FROM_EMAIL = 'username@gmail.com'
SEATABLE_SERVER_EMAIL = 'username@gmail.com'
```
=== "Configuration file (deprecated)"
```python
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = 'username@gmail.com'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = 'username@gmail.com'
SERVER_EMAIL = 'username@gmail.com'
```
Google blocks by default external apps to authenticate against their SMTP servers. To enable SeaTable to send emails via your gmail account, you have two possibilities:
1. If you have enabled 2-step-verification in your Gmail settings, you'll need an [App Password](https://support.google.com/accounts/answer/185833) instead of your login password.
2. If you haven't enabled 2-step-verification in your Gmail settings, you must then enable [Less Secure Apps](https://support.google.com/accounts/answer/6010255).
### Brevo
SeaTable Cloud uses the SMTP relay of Brevo.
=== "Environment variables"
```python
SEATABLE_EMAIL_USE_TLS = True
SEATABLE_EMAIL_HOST = 'smtp-relay.sendinblue.com'
SEATABLE_EMAIL_HOST_USER = 'username@domain.com'
SEATABLE_EMAIL_HOST_PASSWORD = 'xsmtpsib-xxx'
SEATABLE_EMAIL_PORT = 587
SEATABLE_DEFAULT_FROM_EMAIL = 'SeaTable '
SEATABLE_SERVER_EMAIL = 'noreply@domain.com'
```
=== "Configuration file (deprecated)"
```ini
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp-relay.sendinblue.com'
EMAIL_HOST_USER = 'username@domain.com'
EMAIL_HOST_PASSWORD = 'xsmtpsib-xxx'
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = 'SeaTable '
SERVER_EMAIL = 'noreply@domain.com'
```
### Infomaniak
If you are using Infomaniak as email server, you can use the following settings.
=== "Environment variables"
!!! warning "SSL support missing"
Infomaniak requires SSL instead of TLS. Configuring this via environment variables is only possible as of v6.1.
Please use the configuration file approach instead in case you haven't upgraded yet.
```ini
SEATABLE_EMAIL_USE_TLS=false
SEATABLE_EMAIL_USE_SSL=true
SEATABLE_EMAIL_HOST='mail.infomaniak.com'
SEATABLE_EMAIL_HOST_USER='username@domain.com'
SEATABLE_EMAIL_HOST_PASSWORD='password'
SEATABLE_EMAIL_PORT=465
SEATABLE_DEFAULT_FROM_EMAIL='SeaTable '
SEATABLE_SERVER_EMAIL='noreply@domain.com'
```
=== "Configuration file (deprecated)"
```python
EMAIL_USE_TLS = False
EMAIL_USE_SSL = True
EMAIL_HOST = 'mail.infomaniak.com'
EMAIL_HOST_USER = 'username@domain.com'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_PORT = 465
DEFAULT_FROM_EMAIL = 'SeaTable '
SERVER_EMAIL = 'noreply@domain.com'
```
---
Source: https://admin.seatable.com/configuration/roles-and-permissions/
# Roles and Permissions
In SeaTable Enterprise Edition, user and administrator roles determine a user's/an administrator's permissions and quotas. (For org users, some permissions and quotas are also determined by the role assigned to the organization.)
All changes relating to the SeaTable's roles are done in the configuration file `dtable_web_settings.py`.
NOTE: Admin privileges are not part of the user role.
## User Roles
A user role is comprised of up to 10 permissions and up to 7 quotas. If a permissions or a quota is not specifically set in a role, the permission is assumed to be given (default value = True) and no quota is applied (default value = no value or empty string).
### User Permissions
The following permissions are supported in user roles:
| Permission | Added in version | Permission to ... | Additional information |
| ------------------------------ | ---------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| can_add_dtable | 1.0 | Create bases | If set to False, the user cannot create bases, neither under "My bases" nor in groups. |
| can_add_group | 1.0 | Create groups | If set to False, the user cannot create groups. The permission can_add_dtable is necessary to create bases inside a group. |
| can_generate_external_link | 1.0 | Create external links | If set to False, the user cannot create external links. (The menu item "External link" in the share dialog is hidden.) |
| can_create_common_dataset | 1.0 | Create common datasets (CDS) | If set to False, the user cannot create CDS. |
| can_use_advanced_permissions | 1.1 | Use advanced permissions | Advanced permissions include table permissions, column permissions, view share, custom sharing permissions, and row locking. |
| can_run_python_script | 1.4 | Run Python scripts | If set to False, the action "Run script" in the button column and "Run script" in the script side panel are disabled; in automation rules, the action "Run Python script" is not available. The execution of Python scripts requires the installation of [Python Pipeline](../installation/components/python-pipeline.md). Does not apply to org users and group bases. |
| can_use_advanced_customization | 2.0 | Use advanced customizations | Advanced customization includes custom team logo, custom form logo, custom URL for forms and app, base security settings, and role permissions in apps. |
| can_use_external_app | 2.2 | Create and manage apps | If set to False, the user cannot create apps or access apps in edit mode. (The app-icon is hidden in the base.) |
| can_use_automation_rules | 2.2 | Create and manage automation rules | If set to False, the user cannot create or modify automation rules. (The menu item "Automation rules" is hidden in the base.) Does not apply to org users and group bases. |
| can_archive_rows | 2.3 | Manage big data and move rows into the big data storage | If set to False, the user cannot enable/disable big data management in a base, nor can the user move rows into the big data storage; if set to False, but big data is enabled in a base, the user can create and access big data views as well as unarchive rows. |
The default value for all permissions is True. This means that if a permission is not specifically set, the role grants the permission.
### User Quotas
The following quotas are supported in user roles:
| Quota | Added in version | Description | Additional information |
| -------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| role_asset_quota | 1.0 | Total storage quota for all personal bases: '1G' means a limit of one gigabyte for files and images (assets); '' means no storage quota for assets | Assets in shared bases owned by another user and assets in group bases do not count against the storage quota. Does NOT apply to org users. |
| row_limit | 1.0 | Total row limit for all personal bases: 10000 means a limit of 10 000 rows; -1 means no row limit | Rows in shared bases owned by another user, rows in group bases, and rows in the big data storage do not count against the row limit. Does NOT apply to org users. |
| big_data_row_limit | 3.1 | Total row limit in big data storage for all bases: 100000 means a limit of 100 000 rows | This item is used for the role of teams rather than users. Does NOT apply to org users. |
| big_data_storage_quota | 4.3 | Total storage quota for all bases in big data storage: '1G' means a limit of one gigabyte; '' means no storage quota for big data storage. | Assets in rows in the big data storage do not count against this quota. This item is used for the role of teams rather than users. Does NOT apply to org users. |
| scripts_running_limit **(Deprecated)** | 2.3 | Total number of _Python_ scripts run within a month: 100 means 100 script runs per month; -1 means unlimited script runs | The script run counter is reset at the beginning of every month. This quota can only be configured up until (and including) version 6.1. |
| scripts_running_limit_per_user | 6.2 | The maximum number of _Python_ script runs per user per month. In team mode, the total number of script runs within the team will be shared. `-1` allows for an unlimited number of script runs. | The script run counter is reset at the beginning of every month. |
| snapshot_days | 2.1 | Retention period for snapshots in days: 180 means a storage period of 180 days; no value means an unlimited retention period | Snapshots older than the retention period are automatically removed. |
| share_limit | | Max number of users a base can be shared with: 100 means a base can be shared with 100 users | |
| ai_credit_per_user | 6.0 | The maximum AI quota allowed per user per month (i.e., the maximum amount of tokens that can be used in a single month, converted into an amount. In team mode, the total quota within the team will be shared). `-1` means unlimited quota. | |
| monthly_automation_limit_per_user | 6.1 | The maximum number of automation executions per user per month. In team mode, the total number of allowed executions within the team will be shared. `-1` allows for an unlimited number of executions. | |
### Standard User Roles
SeaTable has two standard, preconfigured user roles `default` and `guest`. They can be used in the Users' section of the system administration without prior configuration.
The standard user roles are defined as follows:
```python
ENABLED_ROLE_PERMISSIONS = {
'default': {
'ai_credit_per_user': -1,
'big_data_storage_quota': '',
'can_add_dtable': True,
'can_add_group': True,
'can_archive_rows': True,
'can_create_common_dataset': True,
'can_generate_external_link': True,
'can_invite_guest': False,
'can_run_python_script': True,
'can_use_advanced_customization': True,
'can_use_advanced_permissions': True,
'can_use_automation_rules': True,
'can_use_external_app': True,
'can_use_global_address_book': True,
'monthly_api_call_limit_per_user': -1,
'monthly_automation_limit_per_user': -1,
'role_asset_quota': '',
'role_quota': '',
'row_limit': -1,
'scripts_running_limit_per_user': -1,
'share_limit': 100,
'snapshot_days': 180
},
'guest': {
'ai_credit_per_user': -1,
'big_data_storage_quota': '',
'can_add_dtable': False,
'can_add_group': False,
'can_archive_rows': True,
'can_create_common_dataset': True,
'can_generate_external_link': True,
'can_invite_guest': False,
'can_run_python_script': True,
'can_use_advanced_customization': True,
'can_use_advanced_permissions': True,
'can_use_automation_rules': True,
'can_use_external_app': True,
'can_use_global_address_book': False,
'monthly_api_call_limit_per_user': -1,
'monthly_automation_limit_per_user': -1,
'role_asset_quota': '',
'role_quota': '',
'row_limit': -1,
'scripts_running_limit_per_user': -1,
'share_limit': 100,
'snapshot_days': 30
},
}
```
If you want to modify the permissions and quotas of either or both standard roles, copy-and-paste the above codeblock into `dtable_web_settings.py` and modify as per your needs. Restart SeaTable for the changes to take effect.
### Custom User Roles
You can add additional user roles by extending the codeblock in `dtable_web_settings.py`. A custom user role inherits all permissions and quotas of the role `default`; you only need to list the values that shall differ.
To add a role `employee`, for example, add the following lines (beginning at `'employee'` and ending at `},` ) to the existing role definition.
```python
ENABLED_ROLE_PERMISSIONS = {
'employee': {
'can_add_dtable': True,
'can_add_group': False,
'can_create_common_dataset': False
},
}
```
Restart SeaTable for the new role to become available in SeaTable.
## Administrator Roles
Similar to a user role, an administrator role is comprised of several permissions, but no quotas.
User roles and administrator roles behave in opposite ways when a permission is not set: a user role grants everything that is not explicitly listed, an administrator role grants **nothing** that is not explicitly listed. Internally, every administrator role is merged onto a hidden role `dummy_admin` in which all permissions are set to `False`. Consequently, you must list every single permission that an administrator role shall have.
### Administrator Permissions
The following permissions are supported in administrator roles:
| Permission | Added in version | Permission to ... | Additional information |
| --------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| can_view_system_info | 1.0 | See/access "Info" menu in System admin | The license cannot be uploaded with this permission alone. |
| can_view_statistic | 1.0 | See/access "Statistic" menu in System admin | |
| can_config_system | 1.0 | See/access "Settings" menu in System admin | |
| can_manage_user | 1.0 | See/access "Users" menu in System admin | |
| can_update_user | 1.6 | See and modify the details of an individual user | Grants access to a single user account without granting the complete "Users" menu. An administrator with `can_manage_user` has these rights as well. |
| can_manage_group | 1.0 | See/access "Groups" menu in System admin | |
| can_manage_external_link | 1.0 | See/access "External links" menu in System admin | |
| can_view_audit_log | 5.1 | See/access "Audit logs" menu in System admin and its tabs "Action logs", "File access logs" and "Permission logs" | This permission controls the menu itself. Without it, the menu is hidden — even if `can_view_user_log` is set. The tabs besides "Login logs" additionally require the *user* permission `can_use_advanced_permissions`. |
| can_view_user_log | 1.0 | See/access the tabs "Login logs" and "Group member logs" in "Audit logs" menu in System admin | Requires `can_view_audit_log` to make the menu visible. |
| can_view_admin_log | 1.0 | See/access "Admin logs" menu in System admin | |
| can_manage_organization | 2.0 | See/access "Organizations" menu in System admin | The menu is only shown if multi-tenancy is enabled. |
| can_update_organization | 2.2 | See and modify the details of an individual organization | Grants access to a single organization without granting the complete "Organizations" menu. An administrator with `can_manage_organization` has these rights as well. |
| can_manage_app | 5.3 | See/access "Apps" menu in System admin | |
| other_permission | 5.2 | See/access "Virus scan" menu in System admin | Despite its generic name, this permission currently only controls the virus scan records. |
| can_manage_library | 1.0 | Administer libraries via the API | Inherited from Seafile. SeaTable's system administration has no "Libraries" menu, so this permission only guards the corresponding API endpoints. |
| can_manage_base | 2.0 | Administer bases via the API | The "Bases" menu is shown to the role `default_admin` only and cannot be granted to another role. This permission only guards the corresponding API endpoints. |
| can_manage_form | 2.0 | Administer forms via the API | The "Forms" menu is shown to the role `default_admin` only and cannot be granted to another role. This permission only guards the corresponding API endpoints. |
| can_manage_sys_notification | 2.0 | Administer system notifications via the API | The "Notifications" menu is shown to the role `default_admin` only and cannot be granted to another role. This permission only guards the corresponding API endpoints. |
| can_manage_plugin | 2.0 | Administer plugins via the API | The "Plugins" menu is shown to the role `default_admin` only and cannot be granted to another role. This permission only guards the corresponding API endpoints. |
The default value for all permissions is False. This means that if a permission is not specifically set, the role does **not** grant the permission.
### Standard Administrator Roles
SeaTable has four standard, preconfigured administrator roles `default_admin`, `system_admin`, `daily_admin` and `audit_admin`. They can be used in the Users' section of the system administration without prior configuration.
Only an administrator with the role `default_admin` can assign an administrator role to another administrator. All other administrator roles can see the role of an administrator, but not change it.
The standard administrator roles are defined as follows:
```python
ENABLED_ADMIN_ROLE_PERMISSIONS = {
# can do everything
'default_admin': {
'can_view_system_info': True,
'can_view_statistic': True,
'can_config_system': True,
'can_manage_library': True,
'can_manage_user': True,
'can_update_user': True,
'can_manage_group': True,
'can_manage_external_link': True,
'can_view_user_log': True,
'can_view_audit_log': True,
'can_view_admin_log': True,
'can_manage_base': True,
'can_manage_app': True,
'can_manage_form': True,
'can_manage_organization': True,
'can_update_organization': True,
'can_manage_sys_notification': True,
'can_manage_plugin': True,
'other_permission': True,
},
# can ONLY access the "Info" and "Settings" menu
'system_admin': {
'can_view_system_info': True,
'can_config_system': True,
},
# can ONLY access the "Info", "Statistic", "Users", "Groups" and "Audit logs" menu
'daily_admin': {
'can_view_system_info': True,
'can_view_statistic': True,
'can_manage_library': True,
'can_manage_user': True,
'can_update_user': True,
'can_manage_group': True,
'can_view_user_log': True,
'can_view_audit_log': True,
},
# can ONLY access the "Info", "Audit logs" and "Admin logs" menu
'audit_admin': {
'can_view_system_info': True,
'can_view_admin_log': True,
'can_view_user_log': True,
'can_view_audit_log': True,
}
}
```
If you want to modify the permissions of one or more standard administrator roles, copy-and-paste the above codeblock into `dtable_web_settings.py` and modify as per your needs. Restart SeaTable for the changes to take effect.
### Custom Administrator Roles
Just like a user role, you can add additional administrator roles by adding/modifying the following codeblock in `dtable_web_settings.py`.
```python
ENABLED_ADMIN_ROLE_PERMISSIONS = {
'new_admin_role': {
'can_view_system_info': True,
'can_config_system': True,
'can_manage_user': True,
'can_manage_group': True,
'can_view_admin_log': True,
}
}
```
Restart SeaTable for the new role to become available in SeaTable.
The four standard administrator roles (and the two standard user roles) have a translated display name in the web interface: `default_admin` is shown as "Default admin", `system_admin` as "System admin", `daily_admin` as "Daily admin" and `audit_admin` as "Audit admin".
For every other role, SeaTable falls back to the key you defined. A role `new_admin_role` therefore appears as `new_admin_role` in the role dropdown of the Users' section — underscores included. If you want a nice-looking entry, choose the key accordingly, e.g. `Support` instead of `support_admin_role`.
---
Source: https://admin.seatable.com/configuration/universal-apps/
# Universal apps
Since Version 4.0, universal apps are enabled by default.
Before that version, universal app could be enabled with the following parameter in `dtable_web_settings.py`.
```bash
ENABLE_UNIVERSAL_APP = True
```
## Maps Page Type
The "Maps" page type requires the configuration of an API key for Google Maps.
It will only be visible once you've configured the variable `DTABLE_GOOGLE_MAP_KEY` inside `dtable_web_settings.py`.
Please refer to the [this page](plugins.md#map-plugin) for detailed instructions.
---
Source: https://admin.seatable.com/configuration/autostart/
# Autostart
## Autostart of the docker container
In all our `yml` files, we have specified `restart: unless-stopped`. The function specifies that the container should always restart if it exits for any reason—except if it was explicitly stopped by a user or administrator. This policy keeps your container running persistently unless you intentionally stop it.
## Autostart of SeaTable service
When you start the SeaTable Docker container, the SeaTable service and all its components launch automatically. There are only a few exceptions where this does not happen, such as when specific advanced configurations are in place:
## Deactivate Autostart
There are situations under which the SeaTable service does not start automatically:
1. you set the `.env` Variable `SEATABLE_START_MODE=cluster`
2. there is a `seatable-controller.conf` in the `conf` directory
In both cases SeaTable expects to be part of an advanced setup where the service should not be started automatically. So if SeaTable service does not start automatically, check first, if one of these two situations are true.
Otherwise check the logs of your container with `docker logs seatable-server`.
---
Source: https://admin.seatable.com/configuration/base-rows-limit/
# Base supported rows limit
By default, a base contains up to 100,000 rows (excluding archived rows). Above 100,000 rows, the base will become read-only. If more than 150,000 rows, the base will fail to load.
Base rows are limited for the following technical reasons:
* The base is read from the persistent storage (dtable-storage-server) into the memory of dtable-server, and the maximum support size is 600M. This is a limitation of Node.js technology, because a string in Node.js cannot exceed 600M. For safety reason, dtable-server will not attempt to load this base when it exceeds 300M. (Attachments in the base are not counted.)
* When the base is too large, it takes too much time for the server to serialize it and send it to the network when the client loads the base. At this time, the server cannot respond to other requests.
Starting from version 3.4, for private deployment users, if your application scenario needs to support more than 100,000 rows in a base, but the storage space occupied by the base itself is not large (for example, it contains a large number of blank cells), you can modify the server's configuration, to support more than 100,000 rows.
## dtable-server
The configuration depends on your SeaTable version::
=== "SeaTable <= v6.1"
The following parameters must be added to `dtable_server_config.json`:
```json
{
"base_writable_limit": 100000,
"base_max_rows_limit": 150000
}
```
=== "SeaTable v6.2+"
Two environment variables must be configured.
Please read our [guide](./customizations.md) that explains how to configure these additional environment variables before proceeding.
```ini
BASE_WRITABLE_LIMIT=100000
BASE_MAX_ROWS_LIMIT=150000
```
Among them, `base_writable_limit` is used to limit the rows written into the base. `base_max_rows_limit` is used to control when the rows in the base is greater than the number, the server refuses to load the base into memory. `base_max_rows_limit` needs to be greater than `base_writable_limit`.
## dtable-web
`dtable_web_settings.py`
```python
BASE_WRITABLE_LIMIT = 100000
```
This is used to let the Web UI to become read-only when rows exceed the limit.
---
## User Hierarchy
Source: https://admin.seatable.com/configuration/user-hierarchy/overview/
# User Hierarchy
SeaTable provides several levels of user organization to match different deployment scenarios — from small teams to large multi-tenant installations.
## Overview
| Level | Purpose | Default | Typical use case |
|---|---|---|---|
| **Users** | Individual accounts | Always active | Every installation |
| **[Groups](groups.md)** | Collaborate on shared bases | Always active | Any installation |
| **[Teams/Organizations](teams-organizations.md)** | Fully isolated tenants | Disabled | Multi-tenant / SaaS deployments |
| **[Departments](departments.md)** | Hierarchical org structure | Enabled | Enterprises with formal org charts |
## How they relate
- **Users** are the foundation — every person has an account.
- **Groups** allow users to share bases and collaborate. Any user can create a group (unless restricted by [roles](../roles-and-permissions.md)).
- **Teams/Organizations** provide full tenant isolation. Users within one team cannot see users or bases of another team. This is the mode used by cloud.seatable.io.
- **Departments** add a hierarchical structure on top of groups, where members of a sub-department are automatically members of all parent departments.
---
Source: https://admin.seatable.com/configuration/user-hierarchy/groups/
# Groups
Groups are SeaTable's primary collaboration feature. Members of a group can share bases with the entire group instead of sharing with individual users.
Groups are always enabled and require no configuration to use.
## Group roles
Each group has three roles:
- **Owner**: The user who created the group. Can transfer ownership, manage members, and delete the group.
- **Admin**: Can manage members and shared bases within the group.
- **Member**: Can access bases shared with the group.
## Configuration options
### Restrict group creation
By default, every user can create groups. To restrict this, configure a custom [role](../roles-and-permissions.md) with `can_add_group` set to `False`.
### Member limit
The maximum number of members per group is controlled by the following setting in `dtable_web_settings.py`:
```python
GROUP_MEMBER_LIMIT = 500
```
The default value is `500`.
### Automatic group management via LDAP
Groups can be automatically created and managed through LDAP synchronization. See the [LDAP configuration](../authentication/ldap.md) for details.
---
Source: https://admin.seatable.com/configuration/user-hierarchy/teams-organizations/
# Teams / Organizations
Teams/Organizations provide full tenant isolation for multi-tenant deployments. Users within one team cannot see users, groups, or bases of another team. This is the mode used by cloud.seatable.io.
Yes. **Organization** is the technical term used in configuration files and the API. **Team** is the user-facing term used in cloud.seatable.io. They refer to the same concept.
## Enable teams
Add these two settings to `dtable_web_settings.py`:
```python
CLOUD_MODE = True
MULTI_TENANCY = True
```
After a [restart](../../maintenance/restart-seatable.md), the system admin can create and manage organizations in the **System Admin** area.
## What changes when teams are enabled
Enabling `CLOUD_MODE` and `MULTI_TENANCY` fundamentally changes how SeaTable operates:
- **User isolation**: Users can only see members of their own team
- **Separate admin layer**: Each team gets its own **Team Admin** who can manage users, groups, and bases within the team
- **Independent user management**: The system admin creates organizations and assigns an initial team admin. From there, the team admin manages the team independently.
- **Quota enforcement**: Each organization can have its own limits for rows, storage, API calls, and more
## Organization quotas
The system admin can configure per-organization quotas. These can be set via the **System Admin** web interface or the API:
| Quota | Description |
|---|---|
| **Member quota** | Maximum number of users in the organization |
| **Row limit** | Maximum number of rows across all bases |
| **Big data row limit** | Maximum number of rows in big data storage |
| **Asset quota** | Maximum storage for files and images |
| **Monthly API calls per user** | Rate limit for API usage |
| **Monthly automations per user** | Rate limit for automation runs |
## Team admin settings
Team admins can configure the following settings for their organization:
| Setting | Description |
|---|---|
| **Force two-factor authentication** | Require 2FA for all team members |
| **Force SSO login** | Require single sign-on for all team members |
| **Allow members to modify their name** | Let users change their display name |
| **Send welcome email to new users** | Notify new members by email |
## Additional settings
### Member quota defaults
To set a default member quota for new organizations, add to `dtable_web_settings.py`:
```python
ORG_MEMBER_QUOTA_ENABLED = True
ORG_MEMBER_QUOTA_DEFAULT = 10
```
### Organization logos
To allow team admins to upload a custom logo for their organization:
```python
ENABLE_ORG_LOGO = True
```
---
Source: https://admin.seatable.com/configuration/user-hierarchy/departments/
# Departments
Departments extend SeaTable's group concept with a hierarchical structure. They allow you to map your organization's structure (e.g. divisions, teams, units) directly into SeaTable.
## How departments differ from groups
| | Groups | Departments |
|---|---|---|
| Structure | Flat | Hierarchical (parent/child) |
| Membership | Explicit only | Automatic inheritance from sub-departments |
| Creation | Any user (if permitted) | System admin or team admin only |
| Enabled by default | Yes | Yes |
When a user is added to a sub-department, they automatically become a member of all parent departments above it.
## Disable departments
Departments are enabled by default. If you don't want to use departments, set the following in `dtable_web_settings.py`:
```python
ENABLE_ADDRESSBOOK_V2 = False
```
Changes to `dtable_web_settings.py` require a [restart](../../maintenance/restart-seatable.md) of SeaTable.
## Manage departments
Once enabled, departments are managed in the admin areas:
- The **system admin** creates and manages departments under **System Admin > Departments**.
- In multi-tenant setups, **team admins** manage the departments of their own team under **Team Admin > Departments** (see [`ENABLE_ORG_DEPARTMENT`](#enable-departments-within-teams) below).
Departments can be nested to any depth. Each department member is either a *Default member* or an *Admin*. Department admins can manage the members of their department and of all its sub-departments.
Departments can also be populated automatically from an LDAP or Active Directory server, see [`SYNC_GROUP_AS_DEPARTMENT`](../authentication/ldap.md).
## Additional settings
The following settings are optional. The values shown are the defaults in SeaTable 6.2.
### Enable departments within teams
```python
ENABLE_ORG_DEPARTMENT = True
```
If you use [teams/organizations](teams-organizations.md), this setting allows team admins to create and manage departments within their team. Set it to `False` to restrict department management to the system admin.
### Let users browse the bases of department members
```python
ENABLE_DEPARTMENT_ADMIN_MANAGE_MEMBER_BASES = False
```
If enabled, a **Departments** entry is added to the navigation of every user. There, users can browse the departments they belong to, including sub-departments and their members. Users in a parent department can also open the bases owned by members of its sub-departments with read-only permission.
---
## Authentication
Source: https://admin.seatable.com/configuration/authentication/overview/
# Authentication
SeaTable Server Enterprise Edition (SeaTable) supports multiple authentication types.
The default authentication type is authentication against the local user database with or without [two-factor authentication](./two-factor-auth.md).
Additionally, SeaTable supports the following external authentication types:
- [LDAP (Auth and Sync)](./ldap.md)
- [OAuth](./oauth.md)
- [SAML](./saml.md)
Finally, users can also authenticate using [JWT](./jwt.md), which may be interesting for some special use cases.
The local database authentication is always available, which means that an administrator can always sign in with a local password. In addition, you can enable several external methods at the same time.
By default, each method identifies a user by its own `uid` and creates a **separate** account with a separate `username`. This also happens when LDAP, SAML, or OAuth refer to the same physical person. There is one exception: LDAP and SAML can be tied to a **single shared account** with `LDAP_SAML_USE_SAME_UID`, in which case SAML handles login and LDAP handles synchronization only. See [LDAP › LDAP and SAML](./ldap.md#ldap-and-saml). OAuth has no comparable account-sharing option.
Note also that the login page exposes a single **Single Sign-On** button: if both SAML and OAuth are enabled, it always routes to SAML.
## Username
SeaTable assigns every user a unique `username`, regardless of the authentication type used. The `username` serves as a key to link the different SQL database tables.
The `username` looks like this: `b7bd00e840a14b748ce2bffdf409488b@auth.local` The corresponding regular expression is `^[a-f0-9]{32}(@auth.local)$`. The part of the username in front of the @-sign is a random value. If a user account is deleted and recreated with exactly the same details, the new `username` will be different from the previous one.
The `username` is generated when the account is created. The time at which SeaTable creates the account in the database depends on the authentication type:
- Local user database: when the administrator registers the user or when the user self-registers
- LDAP Auth, OAuth, and SAML: when the user logs in for the first time
- LDAP Sync: when the sync job runs for the first time after the corresponding modification in the LDAP directory
For historical reasons, the SQL database tables use non-uniform names for `username`. In some tables, `username` is simply `user`. In some others, it goes by the name of `email` or `virtual_id`. Despite the inconsistent naming, it is always the same object. In the SeaTable Manual, only `username` is used unless reference is made to a specific table column.
## Database Structure
SeaTable's databases encompass almost 100 tables. Four of those are relevant for user management and authentication. (Tables related to 2FA are disregarded in this document.)
| Database | Table |
| :-------- | :-------------------------------------------------------------- |
| ccnet_db | [`EmailUser`](#table-emailuser) |
| dtable_db | [`profile_profile`](#table-profile_profile) |
| dtable_db | [`social_auth_usersocialauth`](#table-social_auth_usersocialauth) |
| dtable_db | [`id_in_org_tuple`](#table-id_in_org_tuple) |
Note: The table `LDAPUsers` in `ccnet_db` is no longer used.
The database tables shown in the following sections are for illustrative purposes only. Yet, they represent a possible system configuration and are internally consistent.
### Table `EmailUser`
The table EmailUser stores all user accounts of a SeaTable Server with the account status and privileges for every user account. Additionally, the table also contains the (hashed) passwords for all users that authenticate directly against SeaTable.
```sql
mysql> select email,is_staff,is_active,left(passwd,25) from ccnet_db.EmailUser;
+---------------------------------------------+----------+-----------+---------------------------+
| email | is_staff | is_active | left(passwd,20) |
+---------------------------------------------+---------------------------+----------+-----------+
| b7bd00e840a14b748ce2bffdf409488b@auth.local | 1 | 1 | PBKDF2SHA256$10000$4cd... |
| 12ae56789f1e4c8d8e1c31415867317c@auth.local | 0 | 1 | PBKDF2SHA256$10000$736... |
| 145504ae043c438cbb55f2afb084d586@auth.local | 0 | 1 | ! |
| 91e3f171e9214b0cab6418abfb70bc53@auth.local | 0 | 1 | ! |
| 1a8d6725c4ae40c688b40028fd62c73f@auth.local | 0 | 1 | ! |
+---------------------------------------------+---------------------------+----------+-----------+
```
`is_staff` determines whether the user has system administrator privileges. `is_staff` accepts only 0 (False) and 1 (True) as values.
`is_active` determines whether the user is active. Only active users can log into SeaTable. `is_active` also accepts only 0 (False) and 1 (True) as values.
**Users with a password in the local SQL database:**
SeaTable stores the passwords in the database as hash values. Every password hash starts with `PBKDF2SHA256$10000$` which means that the password was hashed using the PBKDF2SHA256 algorithm and that 10.000 iterations where used (more about [PBKDF2 on Wikipedia](https://en.wikipedia.org/wiki/PBKDF2)).
The first two users in the sample table above are users using the default authentication type. The first of the two is system administrator.
**External authentication:**
A `!` instead of a hash value means that the user uses _external authentication_. The table, however, does not contain the information of which authentication type.
The last three users in the sample table above are users authenticating using either LDAP, OAuth, or SAML.
### Table `profile_profile`
The table `profile_profile`, as the name indicates, contains profile information for every user in the system such as nickname, interface language, and contact email address. Every record in the table `EmailUser` has its correspondence in `profile_profile`.
```sql
mysql> select user,nickname,lang_code,contact_email,login_id from dtable_db.profile_profile;
+---------------------------------------------+--------------+-----------+-------------------+----------+
| user | nickname | lang_code | contact_email | login_id |
+---------------------------------------------+--------------+-----------+-------------------+----------+
| b7bd00e840a14b748ce2bffdf409488b@auth.local | admin | en | admin@seatable.io | NULL |
| 12ae56789f1e4c8d8e1c31415867317c@auth.local | Test | en | test@seatable.io | NULL |
| 145504ae043c438cbb55f2afb084d586@auth.local | Hulk | en | hulk@seatable.io | hulk |
| 91e3f171e9214b0cab6418abfb70bc53@auth.local | Tony Stark | en | tony@seatable.io | tony |
| 1a8d6725c4ae40c688b40028fd62c73f@auth.local | Steve Rogers | en | steve@seatable.io | steve |
+---------------------------------------------+--------------+-----------+----------+-------------------+
```
`nickname` is the display name of the user in the web interface of SeaTable.
`contact_email` is the real email address of the user. SeaTable sends notifications to this address.
`login_id` is an alternative to the username that the user can use to log in. The `login_id` can only be set via [SeaTable API](https://api.seatable.com/reference/update-user) and not in system administration in SeaTable's web interface.
Users authenticating against the local database can use the following three combinations to login:
1. `contact_email` + `password`
2. `login_id` + `password`
3. `username` + `password`
### Table `social_auth_usersocialauth`
The table `social_auth_usersocialauth` is critical for external authentication with LDAP, SAML, or OAuth. This table maps the user's SeaTable username to its unique identifiers from the identity providers. Every record in the table `EmailUser` without a password must have at least one correspondence in this table to be able to log into SeaTable using _external authentication_.
```sql
mysql> select username,provider,uid from dtable_db.social_auth_usersocialauth;
+---------------------------------------------+----------------+--------------------------------------+
| username | provider | uid |
+---------------------------------------------+----------------+--------------------------------------+
| 145504ae043c438cbb55f2afb084d586@auth.local | OAuth | 877e1964-5585-4e1a-b069-1951ff79d373 |
| 91e3f171e9214b0cab6418abfb70bc53@auth.local | Authentik-SAML | 28347@authentik |
| 1a8d6725c4ae40c688b40028fd62c73f@auth.local | my-ldap | 39731673920273 |
+---------------------------------------------+----------------+--------------------------------------+
```
`provider` specifies the external authentication used. The name shown in this column is the name specified in the configuration of the external authentication source in `dtable_web_settings.py`.
`uid` in this table is the unique identifier as communicated by the external authentication service. The `uid` has to be provided by the external authentication method and allows to match the users from the external service with the users inside SeaTable. This `uid` must not be changed over the lifetime of the user (despite name, email address, ... changes) If the `uid` changes, SeaTable considers the user as a new user and creates a new `username` accordingly.
### Table `id_in_org_tuple`
This table stores the user IDs. Because setting a user ID is optional, this table can be significantly shorter than all the other three tables.
```sql
mysql> select * from dtable_db.id_in_org_tuple;
+---------------------------------------------+-----------+--------+
| virtual_id | id_in_org | org_id |
+---------------------------------------------+-----------+--------+
| b7bd00e840a14b748ce2bffdf409488b@auth.local | 21 | -1 |
| 145504ae043c438cbb55f2afb084d586@auth.local | 222 | 12 |
| 91e3f171e9214b0cab6418abfb70bc53@auth.local | 333AZE | 34 |
| 1a8d6725c4ae40c688b40028fd62c73f@auth.local | EF_3479 | -1 |
+---------------------------------------------+-----------+--------+
```
`id_in_org` is the ID of the user. The user ID can be an alphanumeric string and must be unique within every team/organization.
`org_id` is the id of the team/organization which is unique in the system. An `org_id` value of -1 signifies that the user does not belong to any team/organization.
---
## Methods
Source: https://admin.seatable.com/configuration/authentication/two-factor-auth/
# Two-Factor Authentication
Two-factor authentication (2FA) provides an extra layer of security against unauthorized access by requiring an additional piece of information besides **username and password**.
SeaTable supports time-based, one-time passwords (TOTP) as a second factor with the default authentication.
A TOTP app such as Google Authenticator or [2FAS](https://2fas.com/) is required to use 2FA with SeaTable.
## Global Configuration
To enable 2FA, add the following configuration in the configuration file `dtable_web_settings.py`:
```python
ENABLE_TWO_FACTOR_AUTH = True # Default value is False.
```
Optionally, 2FA can be enforced for all users. If you wish to do that, add the following configuration to `dtable_web_settings`:
```python
ENABLE_FORCE_2FA_TO_ALL_USERS = True # Default value is False.
```
Note: When disabling 2FA enforcement by changing `True` to `False`, 2FA is disabled for all users.
## User-specific Configuration
System and team administrators can enforce 2FA for individual users in system and team administration of SeaTable's web interface, respectively.
---
Source: https://admin.seatable.com/configuration/authentication/ldap/
# LDAP
Lightweight Directory Access Protocol (LDAP) is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services. Microsoft's Active Directory (AD) is fully compatible with LDAP. For simplicity, this Manual refers to LDAP and AD when using the term LDAP unless explicitly stated otherwise.
This document assumes that you have a basic understanding of LDAP and that you understand the related terminology.
## LDAP integration in SeaTable
SeaTable supports two modes of operation with LDAP:
- LDAP authentication: SeaTable uses the LDAP Server for user authentication.
- LDAP synchronisation: SeaTable syncs users and groups with the LDAP server regularly.
Regardless of the mode of operation used, SeaTable requires each user in the LDAP server to have a unique ID.
Additionally, LDAP in SeaTable can be configured to work seamlessly with SAML.
## LDAP Authentication
To enable LDAP Authentication (LDAP Auth), add the following parameters to `dtable_web_settings.py`, customize to your environment, and [restart SeaTable](../../maintenance/restart-seatable.md):
| Parameter | Description | Values |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| ENABLE_LDAP | On/off switch for authentication via LDAP | `True` or `False` |
| LDAP_PROVIDER | Internal name to refer to LDAP as authentication type | Alphanumeric string, e.g. 'ldap' |
| LDAP_SERVER_URL | URL of the LDAP server and port if non-standard | URL, e.g. 'ldap://192.168.0.10:389' |
| LDAP_BASE_DN | DN of the root node used for querying users - all users under this node can log in | LDAP DN |
| LDAP_ADMIN_DN | DN of the user used for querying the LDAP server - user must have the rights to access all information under LDAP_BASE_DN | For LDAP: LDAP DN For AD: LDAP DN or email |
| LDAP_ADMIN_PASSWORD | User password for LDAP_ADMIN_DN user | Alphanumeric string |
| LDAP_LOGIN_ATTR | User attribute used for logging in | 'mail', 'userPrincipalName' or 'sAMAccountName' |
This is a simple sample configuration:
```python
ENABLE_LDAP = True
LDAP_PROVIDER = 'ldap'
LDAP_SERVER_URL = 'ldap://192.168.0.10'
LDAP_BASE_DN = 'ou=test,ou=test,dc=example,dc=com'
LDAP_ADMIN_DN = 'administrator@example.com'
LDAP_ADMIN_PASSWORD = 'secret'
LDAP_LOGIN_ATTR = 'mail'
```
Some tips on how to select LDAP_BASE_DN and LDAP_ADMIN_DN:
- To determine your LDAP_BASE_DN attribute, you first need to open the graphical interface of the domain manager and browse your organizational structure.
- If you want all users in the system to be able to access SeaTable, you can use 'cn=users,dc=yourdomain,dc=com' as the BASE option (need to replace your domain name).
- If you only want people in a certain department to be able to access, you can limit the scope to a certain OU. You can use the `dsquery` command-line tool to find the DN of the corresponding OU. For example, if the name of the OU is `staffs`, you can run `dsquery ou -name staff`. More information can be found [here]().
- Although AD supports the use of usernames in email address format as `LDAP_ADMIN_DN` such as administrator@example.com, it sometimes does not correctly recognize this format. At this point, you can use `dsquery` to find the DN of the user. For example, if the username is `seatableuser`, run `dsquery user -name seatableuser` to find the user. More information can be found [here]().
The following parameters are also available, but optional:
| Parameter | Description | Values |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| LDAP_FILTER | Filter for users who can log in, e.g. a certain security group | LDAP filter, e.g. `memberOf=CN=SeaTable_Users,…` |
| LDAP_USER_UNIQUE_ID | LDAP attribute whose value is stored as the user's `uid` in `social_auth_usersocialauth` and used to recognize a returning user. Choose an attribute that never changes over the user's lifetime, because if it changes, SeaTable treats the user as new. Binary GUID/UUID values are decoded automatically; default value is '' | Attribute name, e.g. `objectGUID` (AD) or `entryUUID` (OpenLDAP) |
| LDAP_GROUP_FILTER | Additional filter applied when searching for groups to synchronize (group sync only). It is combined with the configured group object class using a logical AND. Leave empty to sync all groups of that class; default value is '' | LDAP filter, e.g. `cn=SeaTable*` |
| LDAP_USER_ROLE_ATTR | Name of user role in the LDAP server | Attribute name, e.g. `title` |
| LDAP_USER_FIRST_NAME_ATTR | First part of the user's SeaTable nickname when nickname is spliced; default value is '' | Attribute name, e.g. `givenName` |
| LDAP_USER_LAST_NAME_ATTR | Second part of the user's SeaTable nickname when nickname is spliced; default value is '' | Attribute name, e.g. `sn` |
| LDAP_USER_NAME_REVERSE | Option to reverse order of first name and last name f spliced nickname; default value is `False` | `True` or `False` |
| LDAP_SAML_USE_SAME_UID | Use SAML for login and LDAP only for synchronization, mapping both to one shared account; disables interactive LDAP login (see [LDAP and SAML](#ldap-and-saml)) | `True` or `False` |
| LDAP_CONTACT_EMAIL_ATTR | Alternative attribute as a mail address when LDAP_LOGIN_ATTR is not `mail`; the attribute overrides the email address imported through LOGIN_ATTR; default value is '' | |
| LDAP_EMPLOYEE_ID_ATTR | ID of the employee | Attribute name, e.g. `33` |
To enable LDAP authentication via SASL, add the following parameters to `dtable_web_settings.py`:
| Parameter | Description | Values |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| ENABLE_SASL | On/off switch for LDAP authentication via SASL | `True` or `False` |
| SASL_MECHANISM | SASL mechanism configured on LDAP server | SASL mechanism, e.g. `DIGEST-MD5`, `CRAM-MD5`, `GSSAPI`, `Plain` |
| SASL_AUTHC_ID_ATTR | User attribute used for [authentication identity mapping](https://www.openldap.org/doc/admin26/sasl.html#Mapping%20Authentication%20Identities) | Attribute name, e.g. `uid`, `cn` |
## LDAP Synchronisation
To enable LDAP synchronisation (LDAP Sync), LDAP Auth must be configured and the following parameters added to `dtable_web_settings`:
| Parameter | Description | Values |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| LDAP_SYNC_GROUP | Whether groups should be synced with the LDAP server. Missing groups in SeaTable are created automatically. Synced users are added as regular group members. | `True` or `False` |
| LDAP_GROUP_MEMBER_ATTR | Attribute used when syncing group members | For most directory servers, the attributes is "member", which is the default value. For "posixGroup", it should be set to "memberUid". |
| LDAP_GROUP_MEMBER_UID_ATTR | User attribute set in 'memberUid' option, which is used in "posixGroup"; default value is `uid` | |
| LDAP_USER_OBJECT_CLASS | Name of the class used to search for user objects; default value is `person` | |
| LDAP_GROUP_OBJECT_CLASS | Name of the class used to search for group objects; default value is `group` | For LDAP: `groupOfNames`, `groupOfUniqueNames`, `posixGroup` For AD: `group` |
| LDAP_GROUP_UUID_ATTR | ...; default value is `ObjectGUID` | For LDAP: refer to [UUID](https://ldapwiki.com/wiki/Universally%20Unique%20Identifier) For AD: `ObjectGUID` |
| SYNC_GROUP_AS_DEPARTMENT | Option to sync LDAP groups as departments rather than SeaTable groups | `True` or `False` |
| LDAP_DEPARTMENT_NAME_ATTR | Name of the department when SYNC_GROUP_AS_DEPARTMENT = True, the default department name is the OU name | Object name, e.g. `description` |
Depending on your SeaTable version, additional settings must be configured:
=== "SeaTable <= v6.1"
The following parameters must be added to `dtable-events.conf`:
```ini
[LDAP SYNC]
enabled = true
sync_interval = 60 # The unit is seconds
```
=== "SeaTable v6.2+"
Two environment variables must be configured.
Please read our [guide](../../configuration/customizations.md) that explains how to configure these additional environment variables before proceeding.
```ini
LDAP_SYNC_ENABLED=true
# Specified in seconds
LDAP_SYNC_INTERVAL=3600
```
## LDAP and SAML
In some situations it is useful to use **SAML for authentication** and **LDAP for synchronization** at the same time. A typical example is a setup where users sign in through an Identity Provider (IdP) via SAML SSO, while the user and group information is provisioned and kept up to date from your LDAP directory.
Without further configuration, SeaTable would treat the LDAP identity and the SAML identity of one and the same person as two different users. Each of them would receive its own `username`, and SeaTable would create two separate accounts. To prevent this, add the following parameter to `dtable_web_settings.py`:
```python
LDAP_SAML_USE_SAME_UID = True
```
### What this setting does
When `LDAP_SAML_USE_SAME_UID = True`:
- **Interactive login via LDAP is disabled.** Users authenticate **only via SAML**. An attempt to log in with LDAP credentials fails with the generic message "Incorrect account or password". This is by design, and nothing is written to `dtable_web.log`.
- **LDAP is used for synchronization only.** The [LDAP Sync](#ldap-synchronisation) job provisions the accounts and keeps users and groups up to date.
- For every user it provisions, LDAP Sync additionally writes a record into `social_auth_usersocialauth` for the SAML provider that maps the user's `username` to the same `uid`. This bridge record is what lets the subsequent SAML login resolve to the account created by LDAP Sync instead of creating a second one.
The three building blocks therefore play these roles:
| Component | Role in combined mode |
| --------- | ------------------------------------------------------------------ |
| SAML | The only interactive login method |
| LDAP Sync | Provisions accounts and groups, and writes the SAML bridge record |
| LDAP Auth | Disabled (its connection settings are still required by LDAP Sync) |
### Requirements
- **LDAP Sync must be configured and enabled** (see [LDAP Synchronisation](#ldap-synchronisation)). The LDAP connection parameters (`LDAP_SERVER_URL`, `LDAP_ADMIN_DN`, `LDAP_ADMIN_PASSWORD`, `LDAP_BASE_DN`, …) are still required, because the sync job uses them. This applies even though interactive LDAP authentication is off.
- **The IdP must send the same `uid` as LDAP.** The value the IdP sends as the SAML `uid` (typically the NameID) must be exactly the value of the LDAP attribute used as the user's login identifier (`LDAP_LOGIN_ATTR`, e.g. `sAMAccountName`).
- **The comparison is case-sensitive.** While `sAMAccountName` is case-insensitive in Active Directory, the `uid` match in `social_auth_usersocialauth` is case-sensitive. If LDAP provides `jdoe` and the IdP sends `JDoe`, the two will not match and a second account is created.
### Typical setup procedure
1. Configure and test [SAML](./saml.md) on its own with a test user, then delete that test account again.
2. Configure [LDAP Synchronisation](#ldap-synchronisation).
3. Set `LDAP_SAML_USE_SAME_UID = True` and [restart SeaTable](../../maintenance/restart-seatable.md).
4. Let the sync job run (or wait for the configured `sync_interval`) so the accounts and their SAML bridge records exist.
5. Users sign in via SAML. Do not offer the LDAP login form in this mode, because an LDAP login attempt always fails by design.
---
Source: https://admin.seatable.com/configuration/authentication/oauth/
# OAuth
OAuth 2.0 is an open standard for delegated authorization that is widely used for single sign-on (SSO). SeaTable can authenticate users against any OAuth 2.0 provider that exposes the standard authorization, token, and user-info endpoints, such as GitHub or Google.
Unlike the [SAML](./saml.md) integration, the OAuth provider is not configured through a metadata document; instead, you enter the provider's endpoints manually.
## Registering the application in the provider
First, register a client application on the OAuth provider (for example on [GitHub](https://github.com/settings/developers)). During registration:
- Note the **Client ID** and **Client Secret**.
- Set the **Redirect URI** (called "Authorization callback URL" on GitHub) to `https:///oauth/callback/`.
## Configuration
To enable OAuth, add the following parameters to `dtable_web_settings.py`, customize the values to your environment, and [restart SeaTable](../../maintenance/restart-seatable.md).
The following parameters are **required**:
| Parameter | Description | Values |
| ----------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| ENABLE_OAUTH | On/off switch for authentication via OAuth | `True` or `False` |
| OAUTH_CLIENT_ID | The Client ID obtained when registering the application | Alphanumeric string |
| OAUTH_CLIENT_SECRET | The Client Secret obtained when registering the application | Alphanumeric string |
| OAUTH_PROVIDER_DOMAIN | Name SeaTable uses internally to distinguish OAuth from other login methods and stored as the `provider` | Alphanumeric string, e.g. `github.com` |
| OAUTH_AUTHORIZATION_URL | The provider's authorization endpoint | URL, e.g. `https://github.com/login/oauth/authorize` |
| OAUTH_TOKEN_URL | The provider's token endpoint | URL, e.g. `https://github.com/login/oauth/access_token` |
| OAUTH_USER_INFO_URL | The provider's user-info endpoint | URL, e.g. `https://api.github.com/user` |
| OAUTH_REDIRECT_URL | The redirect URI registered in the provider (must match exactly) | URL ending in `/oauth/callback/` |
| OAUTH_ATTRIBUTE_MAP | Mapping of the user fields returned by the provider to the user fields in SeaTable (see below) | Key-value pairs |
The following parameters are **optional**:
| Parameter | Description | Values |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| OAUTH_SCOPE | The scopes requested from the provider; default value is '' | List of strings, e.g. `["user"]` |
| OAUTH_ENABLE_INSECURE_TRANSPORT | Allows OAuth over plain HTTP for setups without HTTPS. Required by the underlying `requests-oauthlib` library when no TLS is configured; default value is `False` | `True` or `False` |
| OAUTH_ACCESS_TOKEN_IN_URI | Passes the access token in the query string of the user-info request. Some providers require this; default value is `False` | `True` or `False` |
| OAUTH_CREATE_UNKNOWN_USER | Just-in-time provisioning: create a SeaTable account on first successful login; default value is `True` | `True` or `False` |
| OAUTH_ACTIVATE_USER_AFTER_CREATION | Whether auto-provisioned users are active immediately. Set to `False` to create them inactive and require administrator approval; default value is `True` | `True` or `False` |
This is a sample configuration for GitHub:
```python
ENABLE_OAUTH = True
OAUTH_ENABLE_INSECURE_TRANSPORT = True
OAUTH_PROVIDER_DOMAIN = 'github.com'
OAUTH_CLIENT_ID = 'your-client-id'
OAUTH_CLIENT_SECRET = 'your-client-secret'
OAUTH_REDIRECT_URL = 'https:///oauth/callback/'
OAUTH_AUTHORIZATION_URL = 'https://github.com/login/oauth/authorize'
OAUTH_TOKEN_URL = 'https://github.com/login/oauth/access_token'
OAUTH_USER_INFO_URL = 'https://api.github.com/user'
OAUTH_SCOPE = ["user"]
OAUTH_ATTRIBUTE_MAP = {
"id": "uid",
"name": "name",
"email": "contact_email",
}
```
### OAUTH_ATTRIBUTE_MAP
`OAUTH_ATTRIBUTE_MAP` maps the fields returned by the provider's user-info endpoint to the fields in SeaTable. Each entry has the form `"": ""`, where the two sides behave differently:
- The **key** (left side) is the field name as your provider delivers it, and this is the side you adjust. GitHub, for example, returns the fields `id`, `name`, and `email`.
- The **value** (right side) is the SeaTable target field and is fixed. SeaTable only recognizes the values listed below; any other value is ignored.
So if your provider returns the email address in a field called `mail`, you change only the key, as in `"mail": "contact_email"`.
| SeaTable field (value) | Required | Description |
| ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| uid | yes | The unique identifier by which SeaTable recognizes a returning user. It must never change over the user's lifetime; if it changes, SeaTable creates a new user. |
| name | no | The display name (nickname) of the user in SeaTable |
| contact_email | no | The contact email address of the user in SeaTable |
| user_role | no | The role assigned to the user in SeaTable |
| employee_id | no | The user's ID within the organization (stored as `id_in_org`) |
By default SeaTable creates a user account on the first successful OAuth login (`OAUTH_CREATE_UNKNOWN_USER = True`). To stop new accounts from being created while keeping existing OAuth users working, set `OAUTH_CREATE_UNKNOWN_USER = False`. New users must then be provisioned in SeaTable beforehand, either by an administrator or via import.
To keep auto-provisioning on but have new accounts created in an inactive state that requires administrator approval, set `OAUTH_ACTIVATE_USER_AFTER_CREATION = False`.
## Provider notes
When configuring Google as the OAuth provider, the scope must be set as follows:
```python
OAUTH_SCOPE = [
"openid",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
]
```
Set the authorization, token, and user-info URLs as well as the scope according to the documentation of your OAuth provider. For GitHub, see [Authorizing OAuth apps](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps).
## Testing
After restarting, navigate to the login page of your SeaTable Server, click on **Single Sign-On**, and try to log in. If the configuration is correct, you are redirected to the provider's login. After a successful login you are redirected back to SeaTable.
Check `dtable_web.log` for troubleshooting information if authentication fails.
The login page exposes a single **Single Sign-On** button that routes to one method only. If both SAML and OAuth are enabled at the same time, this button always goes to SAML, and OAuth is never reached through it. Enable only one of the two for interactive login.
## Custom OAuth (advanced)
For providers that cannot be handled by the standard configuration above, SeaTable offers a custom OAuth mode. When `ENABLE_CUSTOM_OAUTH = True`, SeaTable loads custom `custom_oauth_login` and `custom_oauth_callback` functions from `seatable_custom_functions.custom_oauth` in the `conf` directory, allowing you to implement provider-specific login and callback logic yourself.
```python
ENABLE_CUSTOM_OAUTH = True
```
This is an advanced extension point intended for special integrations and requires you to provide the custom Python module. If the module cannot be imported, SeaTable silently falls back to standard OAuth handling.
---
Source: https://admin.seatable.com/configuration/authentication/saml/
# SAML
Security Assertion Markup Language (SAML) is an open standard for exchanging authentication and authorization data between parties. An important use case of SAML is web-browser single sign-on (SSO).
This document assumes that you have a basic understanding of SAML and that you understand the related terminology.
SeaTable's SAML configuration has undergone substantial changes in SeaTable 3.5. It is highly recommended to update to SeaTable 3.5 or younger if you use SAML. The SAML configuration in prior versions is no longer included in this document. You can still find it in Github.
## SSO with SAML in SeaTable
SeaTable supports SSO with SAML. Specifically, SeaTable supports SAML's IdP-init and SP-init authentication flows.
Besides basic authentication and authorization, SeaTable's SAML implementation also allows additional attributes to be set by the IdP. Specifically, the following five SeaTable fields can be populated from IdP attributes:
| Attribute | Description | Stored in database table | ... in column |
| ------------- | ------------------------------ | -------------------------------------------------------------------------------------- | ------------- |
| uid | Unique identifier from the IdP | [dtable_db.social_auth_usersocialauth](./overview.md#table-social_auth_usersocialauth) | uid |
| contact_email | Email address of the user | [dtable_db.profile_profile](./overview.md#table-profile_profile) | contact_email |
| name | Name of the user | [dtable_db.profile_profile](./overview.md#table-profile_profile) | nickname |
| employee_id | User ID (optional) | [dtable_db.id_in_org_tuple](./overview.md#table-id_in_org_tuple) | id_in_org |
| user_role | Name of the role (optional) | ccnet_db.UserRole | role |
SeaTable also supports using SAML for authentication together with LDAP for synchronization. For more information, see [LDAP › LDAP and SAML](./ldap.md#ldap-and-saml).
## Configuration
The SAML configuration proceeds in two phases:
1. IdP: You create a new application in your IdP and configure the application. The IdP-side configuration is concluded with the download of the IdP's signing certificate.
2. SeaTable: You upload the certificate and configure SAML in the config file `dtable_web_settings.py`
SeaTable's SAML configuration must be done manually on the command line. SeaTable does not provide a graphic wizard for configuring SAML. SeaTable cannot be configured by uploading the IdP's `metadata.xml`.
Due to the large number of identity and access management (IAM) solutions, this document explains the SeaTable's SAML SSO configuration in general terms in the rest of this section and showcases the procedure using Microsoft Azure AD (Azure) as one example. (Additional IAM solutions may be added in the future.)
### Creating and configuring a new application in the IdP
Add a new application in the IdP and assign at least one user to this application.
The configuration of SSO with SAML for the just created application involves adding SeaTable's SAML URLs as well as specifying the SAML attributes. The following table contains the relevant URLs in generalized form. Replace `` with the fully qualified domain name (FQDN) of your SeaTable Server.
| Type | URL |
| ------------------------------------ | -------------------------------------------------------- |
| Metadata URL | `https:///saml/metadata/` |
| Assertion consumer service (ACS) URL | `https:///saml/acs/` |
| Service URL | `https:///` |
### Downloading the certificate from the IdP
After creating and configuring the application, download the IdP's signing certificate in PEM format. If the certificate cannot be downloaded in PEM format, download the metadata.xml instead and extract the certificate file from there. The content in the \<\\> tag contains the certificate.
Also note the URL for the IdP's metadata.xml.
### Uploading the IdP's certificate to SeaTable
The IdP's certificate must be saved on the SeaTable Server. The volume of the SeaTable container is the right place. When saved there, the certificate can be used in different SeaTable Docker containers, e.g. when a new container is created during an update.
The default host path for the SeaTable Docker container is `/opt/seatable-server/` which is mapped to `/shared/` in the container. It is recommended to create a directory here. If you decide to create the directory elsewhere - which you can - you'll need to account for the custom path in the following steps.
```bash
$ mkdir /opt/seatable-server/certs/
```
Change into the directory, create a file idp.crt, and open the file with a text editor of your choice (here nano):
```bash
$ cd /opt/seatable-server/certs/
$ touch idp.crt
$ nano idp.crt
```
Paste the content of the certificate in the text editor and save the edits.
Note: You can check the validity of the certificate file using openssl:
```bash
$ openssl x509 -in idp.crt -noout -dates
```
### Creating SeaTable's certificate and key
Create SeaTable's certificate and key using openssl. The two files must be placed in the same directory as the IdP's certificate.
```bash
$ cd /opt/seatable-server/certs/
$ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout sp.key -out sp.crt
```
Once the command has finished, the directory contains three files: `idp.crt`, `sp.crt`, and `sp.key`.
### Modifying the config file in SeaTable
To enable SAML, add the following parameters to `dtable_web_settings.py`, customize the values to your environment, and [restart SeaTable](../../maintenance/restart-seatable.md):
| Parameter | Description | Values |
| ------------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| ENABLE_SAML | On/off switch for authentication via SAML | `True` or `False` |
| SAML_PROVIDER_IDENTIFIER | Name for SAML provider used internally by SeaTable | Alphanumeric string, e.g. `Azure`, `Auth0`, `Authentik` |
| SAML_REMOTE_METADATA_URL | URL of metadata.xml used by SAML IdP | URL of the IdP metadata.xml (see example below) |
| SAML_ATTRIBUTE_MAP | Key-value pairs mapping SAML attributes to local attributes | Key-value pairs (see example below) |
| SAML_CERTS_DIR | Path to certificates within the Seatable Docker container | Path, e.g. `/shared/certs` |
| SAML_CREATE_UNKNOWN_USER | Enables/disables just-in-time user provisioning on first login (optional) | `True` (default) or `False`. With `False`, existing users can still log in, but no new accounts are created |
This is a sample configuration. Adapt the values to your needs.
```python
ENABLE_SAML = True
SAML_PROVIDER_IDENTIFIER = 'MySAMLProvider'
SAML_REMOTE_METADATA_URL = 'https://login.microsoftonline.com/xxx/federationmetadata/2007-06/federationmetadata.xml?appid=xxx'
SAML_ATTRIBUTE_MAP = {
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/uid': 'uid',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'contact_email',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'name',
}
SAML_CERTS_DIR = '/shared/certs'
```
By default SeaTable creates a user account on the first successful SAML login (`SAML_CREATE_UNKNOWN_USER = True`). To stop new accounts from being created while keeping existing SSO users working, set `SAML_CREATE_UNKNOWN_USER = False`. New users must then be provisioned in SeaTable beforehand (by an administrator or via import).
`SAML_ATTRIBUTE_MAP` maps the attributes (claims) sent by your IdP to the fields in SeaTable. Each entry has the form `"": ""`, where the two sides behave differently:
- The **key** (left side) is the attribute name as your IdP sends it, and this is the side you adjust. It is often a claim URI such as `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`.
- The **value** (right side) is the SeaTable target field and is fixed. SeaTable only recognizes the five values listed above (`uid`, `contact_email`, `name`, `employee_id`, `user_role`); any other value is ignored.
The `uid` is the unique identifier from the IdP (not the username within SeaTable) and must never change over the life cycle of the user. If you map a changing value such as the email address to `uid` and that value later changes, SeaTable creates a new user on the next login.
### Testing
Now [restart SeaTable](../../maintenance/restart-seatable.md) to activate the configuration settings.
Navigate to the login page of your SeaTable Server and click on "Single Sign-On" and try to log in. If the configuration is correct, you'll be redirected the IdP's login. Enter the credentials of a user that was assigned to the application created above.
Check `dtable_web.log` for troubleshooting info if authentication fails.
## Configuration Azure
Browse to 'Azure Active Directory' and select 'Enterprise Applications'. In the 'Enterprise applications | All Applications' pane, click on 'New application' to open the 'Browse Azure AD Gallery'. Hit 'Create your own application', enter the name of the application in the input field (e.g. SeaTable), and click 'Create'. (For more information on [how to add an enterprise application](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal) or [how to create and assign a user account to an enterprise application](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-assign-users), see Microsoft's Azure product documentation.) Azure will then create the application and open its overview page (see screenshot below).

Select the just created enterprise application. Click on '2. Set up single sign-on' in the overview page and then select SAML as single sign-on method. All SAML-related parameters for the new application are set in the configurator that now opens.
Step 1 - Basic SAML Configuration: Click on 'Edit' in the top right corner and add SeaTable's metadata URL, ACS URL, and service URL as shown in the screenshot below.

Step 2 - Attributes and Claims: Click on 'Edit' in the top corner and define the claims as shown in the screenshot below.

Step 3 - SAML Certificates: Note the App Federation Metadata URL and download the certificate. The certificate in Base 64 is the correct certificate format.

Proceed with the [upload of the certificate file to SeaTable](#uploading-the-idp's-certificate-to-seaTable). The SAML configuration in `dtable_web_settings.py` should look like this:
```python
ENABLE_SAML = True
SAML_PROVIDER_IDENTIFIER = 'Azure'
SAML_REMOTE_METADATA_URL = 'https://login.microsoftonline.com/826f1810-ccc9-.../federationmetadata/2007-06/federationmetadata.xml?appid=...'
SAML_ATTRIBUTE_MAP = {
'uid': 'uid', #required
'mail': 'contact_email', #required
'name': 'name', #required
'employeeid': 'employee_id', #optional
'jobtitle': 'user_role', #optional
}
SAML_CERTS_DIR = '/shared/certs/'
```
Replace the value of the `SAML_REMOTE_METADATA_URL` with the URL obtained in step 3 above.
## Configuration Okta
Browse to 'Your apps' and switch to the admin mode.

Click on 'Applications' in the navigation on the left and one more time on 'Applications' in the drop-down menu.
Select 'Create App Integration' and choose 'SAML 2.0' as sign-in method. All SAML-related parameters for the new application are defined in the configurator that now opens.

Step 1 - General Settings: Enter the name of the app in the input field and upload an app logo.

Step 2 - Configure SAML: Add the single sign-on URL, the audience URI as well as the attributes as shown in the screenshot below. Finish the IdP-side configuration by clicking the button of the same name.

Step 3 - Feedback: You can skip this step.
An overview of the configuration including all information for the server-side configuration is displayed once you made it past the 'Feedback'. Note the Metadata URL and download the signing certificate.

Switch to the tab 'Assignments', click the 'Assign' button, and add user to the app via 'Assign to People'

Proceed with the [upload of the certificate file to SeaTable](#uploading-the-idps-certificate-to-seatable). The SAML configuration in `dtable_web_settings.py` should look like this:
```Python
ENABLE_SAML = True
SAML_PROVIDER_IDENTIFIER = 'Okta'
SAML_REMOTE_METADATA_URL = 'https://...'
SAML_ATTRIBUTE_MAP = {
'uid': 'uid',
'contact_email': 'contact_email',
'name': 'name',
}
SAML_CERTS_DIR = '/shared/certs'
```
Replace the value of the `SAML_REMOTE_METADATA_URL` variable with the URL obtained above.
Restart the SeaTable service for the changes to take effect.
## Configuration Auth0
Click on 'Applications' in the navigation on the left. Then choose 'Applications' in the drop-down menu to see a list of the apps that have already been configured in your account.
Step 1 - Create Application: Enter the name of the app in the input field, select 'Regular Web Applications', and click on 'Create'.

Step 2 - Addons: Enable 'SAML2 WEB APP'. You will now see the 'SAML Protocol Parameters'. Copy the link of the 'Identity Provider Certificate' and the 'Identity Provider Metadata' in a temporary document.

Next, switch to the 'Settings' tab. Enter the URL of the [SeaTable's assertion consumer service](#Creating-and-configuring-a-new-application-in-the-IdP) in the 'Application Callback URL' field.

Once you did that, scroll down a bit to finish the process by clicking 'enable'.
Proceed with the [upload of the certificate file to SeaTable](#uploading-the-idps-certificate-to-seatable) that you obtained in step 2. The SAML configuration in `dtable_web_settings.py` should look like this:
```Python
ENABLE_SAML = True
SAML_PROVIDER_IDENTIFIER = 'Auth0'
SAML_REMOTE_METADATA_URL = 'https://...'
SAML_ATTRIBUTE_MAP = {
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier': 'uid',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'contact_email',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'name',
}
SAML_CERTS_DIR = '/shared/certs'
```
Replace the value of the SAML_REMOTE_METADATA_URL variable with the URL obtained in step 2.
Restart the SeaTable service for the changes to take effect.
## Configuration Authentik
Click on 'Applications' in the navigation on the left. Then choose 'Applications' in the drop-down menu to see a list of the apps that have already been configured in your account.
**Step 1 - Application**
Enter a name and a slug and click on **Next**.
**Step 2 - Choose A Provider**
Select **SAML Provider**.
**Step 3 - Configure Provider**
Select `default-provider-authorization-explicit-consent (Authorize Application)`.
Under **Protocol settings**, set the **ACS URL** to `https://${SEATABLE_SERVER_HOSTNAME}/saml/acs` and set the **Service Provider Binding** to **Post**.
Under **Advanced protocol settings**, select **authentik Self-Signed Certificate** as the **Signing Certificate** and enable the **Sign assertions** toggle.
**Step 4 - Configure Bindings**
Click on **Next**.
**Step 5 - Review and Submit Application**
Click on **Submit**
---
Next, select **Applications -> Providers** in the left sidebar and select the newly created provider.
You should now see a **Copy download URL** to get the metadata URL and a **Download** button to download the signing certificate button.
Since authentik's download URL returns a 302 redirect, you must run the following command to figure out the _true_ download URL:
```bash
curl ${AUTHENTIK_DOWNLOAD_URL} -I
```
This will display the _true_ download URL in the location header. Take a note of this URL.
You should also download the signing certificate and store it under `/opt/seatable-server/certs`.
You should now run the `openssl` command described above to create `sp.crt` and `sp.key` inside `/opt/seatable-server/certs`.
A basic SAML configuration in `dtable_web_settings.py` for authentik looks like this:
```python
ENABLE_SAML = True
SAML_PROVIDER_IDENTIFIER = 'authentik'
SAML_REMOTE_METADATA_URL = 'YOUR_METADATA_URL'
SAML_ATTRIBUTE_MAP = {
'http://schemas.goauthentik.io/2021/02/saml/uid': 'uid',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress': 'contact_email',
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name': 'name',
}
SAML_CERTS_DIR = '/shared/certs'
```
Replace the value of the SAML_REMOTE_METADATA_URL variable with the URL you obtained via the `curl` command.
Restart the SeaTable service for the changes to take effect.
---
Source: https://admin.seatable.com/configuration/authentication/saml-team/
# SAML Authentication (for multi-tenancy environments)
The Team SAML feature allows each team in a multi-tenant SeaTable environment to configure its own SAML identity provider (IdP) for single sign-on. While the functionality is available in all deployments, configuration only makes sense in environments such as **cloud.seatable.io**, where multiple independent teams share the same infrastructure.
## Activation
in `dtable_web_settings.py` add these settings:
```python
# to activate teams in general
CLOUD_MODE = True
MULTI_TENANCY = True
# to activate multi-saml in general
ENABLE_MULTI_SAML = True
SAML_CERTS_DIR = '/shared/certs'
```
SAML for Teams is also a role permission that has to be assigned to a role.
```python
ENABLED_ROLE_PERMISSIONS = {
'org_default': {
'can_use_saml': True
},
'org_enterprise': {
'can_use_saml': True
}
}
```
Server certificates have to be created in the host system and made available to SeaTable Server.
The generated certificates are valid for 10 years.
```bash
# executed in the host
mkdir /opt/seatable-server/certs
cd /opt/seatable-server/certs
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout sp.key -out sp.crt
```
## Property Mappings
The IDP must provide the following SAML properties:
- `contact_email`
- `name`
- `uid`
The exact configuration depends on your specific IDP.
### Authentik
Create three property mappings of type `SAML Provider Property Mapping` under `Customization -> Property Mappings` with the following settings:
| Name | SAML Attribute Name | Expression |
| ------------- | ------------------- | --------------------------- |
| contact_email | `contact_email` | `return request.user.email` |
| name | `name` | `return request.user.name` |
| uid | `uid` | `return request.user.pk` |
```python
#SAML_CERTS_DIR = '/opt/seatable/seatable-data'
#SAML_ATTRIBUTE_MAP = {
#'uid': 'uid',
# 'contact_email': 'contact_email',
# 'name': 'name',
#}
```
## Cookie Settings
If the SAML provider is on a separate domain (which it will definitely be in case of `cloud.seatable.io`), the following settings must be configured to prevent issues with cross-site cookies:
```python
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'None'
```
---
Source: https://admin.seatable.com/configuration/authentication/jwt/
# JSON Web Tokens
JSON Web Tokens (=JWT) is another authentication type SeaTable provides. It is used by the SeaTable API but it can also be used to allow server-to-server authentication. JWTs are used for example if you switch from [SeaTable Cloud](https://cloud.seatable.io) to the [team administration](https://account.seatable.io) without the need to re-authenticate.
## What is JWT?
JWT is a very popular technology but comes with its share of controversy. Some say you should never use it. Others say JWT authentication is amazing. We think that JWT can be very helpful in some specific scenarios.
If you want to know more about JWT, please read [this article](https://blog.logrocket.com/jwt-authentication-best-practices/).
Here is a short introduction into JWT:
- JWT is an encoded and cryptographically signed URL, that contains a JSON object.
- This json object can contain any kind and amount of data.
- When a server receives this JWT it can guarantee the data it contains can be trusted because it's signed (not encrypted).
- Both parties (sender and receiver) must know a shared secret that is used to sign the JWT request.
## How to configure and use JWT?
To enable the login with JWTs you have to define a secret key in your `dtable_web_settings.py` and [restart SeaTable](../../maintenance/restart-seatable.md):
```python
SSO_SECRET_KEY = 'your-shared-secret-like-a38B232XQJLx392871#2DEF_dowfWE#_39dwefidWFwLw39fDFEF='
```
Afterwards SeaTable allows the login with the following URL `https://cloud.seatable.io/sso-auto-login/?token=...`.
The token is the encoded json object with these elements:
```json
{
"exp": "1682582542",
"user_id": "b7bd00e840a14b748ce2bffdf409488b@auth.local"
}
```
## Examples how to use JWT and generate the login-link
Every programming language offers libraries to sign JWTs. A good place to start looking for such a library is [https://www.jwt.io/libraries](https://www.jwt.io/libraries).
Here is an example with PHP and the [firebase-library](https://github.com/firebase/php-jwt):
```php
// This code generates an URL to login as the user defined in user_id.
// The URL is valid for 30 seconds.
// After successful login, the user jumps to $url_next.
$url_next = "/"
$jwt_signing_key = "your-shared-secret"
$payload = [
"exp" => time() + 30,
"user_id" => "b7bd00e840a14b748ce2bffdf409488b@auth.local",
];
$jwt = \Firebase\JWT\JWT::encode($payload, $jwt_signing_key, 'HS256');
$jwt_url = 'https://cloud.seatable.io/sso-auto-login/?token='. rawurlencode($jwt) . $url_next;
echo $jwt_url;
```
Other examples can be found here:
- [Vue and Node.js](https://blog.logrocket.com/how-to-implement-jwt-authentication-vue-nodejs/)
- [Python](https://medium.com/@apcelent/json-web-token-tutorial-with-example-in-python-df7dda73b579)
---
## Authentication
Source: https://admin.seatable.com/configuration/authentication/auth-switch/
# Switch authentication type
SeaTable Server supports [multiple authentication types](./overview.md). Switching between the types is possible, but any switch requires modifications of SeaTable's databases.
Before manually manipulating your database, make a database backup, so you can restore your system if anything goes wrong!
See more about [make a database backup](../../maintenance/backup-recovery.md).
## Migrating from local user database to external authentication
As an organisation grows and its IT infrastructure matures, the migration from local authentication to external authentication like LDAP, SAML, OAUTH is a common requirement. Fortunately, the switch is comparatively simple.
### General procedure
1. Configure and test the desired external authentication. Note the name of the `provider` you use in the config file. The user to be migrated should already be able to log in with this new authentication type, but he will be created as a new user with a new unique identifier, so he will not have access to his existing bases. Note the `uid` from the `social_auth_usersocialauth` table. Delete this new, still empty user again.
2. Determine the `xxx@auth.local` address of the user to be migrated.
3. Replace the password hash with an exclamation mark.
4. Create a new entry in `social_auth_usersocialauth` with the `xxx@auth.local`, your `provider` and the `uid`.
The login with the password stored in the local database is not possible anymore. After logging in via external authentication, the user has access to all his previous bases.
### Example
This example shows how to migrate the user with the username `12ae56789f1e4c8d8e1c31415867317c@auth.local` from local database authentication to SAML. The SAML authentication is configured in `dtable_web_settings.py` with the provider name `authentik-saml`. The `uid` of the user inside the Identity Provider is `HR12345`.
This is what the database looks like before these commands must be executed:
```sql
mysql> select email,left(passwd,25) from EmailUser where email = '12ae56789f1e4c8d8e1c31415867317c@auth.local';
+---------------------------------------------+------------------------------+
| email | left(passwd,25) |
+---------------------------------------------+------------------------------+
| 12ae56789f1e4c8d8e1c31415867317c@auth.local | PBKDF2SHA256$10000$4cdda6... |
+---------------------------------------------+------------------------------+
mysql> update EmailUser set passwd = '!' where email = '12ae56789f1e4c8d8e1c31415867317c@auth.local';
mysql> insert into social_auth_usersocialauth \
(`username`, `provider`, `uid`, `extra_data`) \
set \
('12ae56789f1e4c8d8e1c31415867317c@auth.local', 'authentik-saml', 'HR12345', '{}');
```
Afterwards the databases should look like this:
```sql
mysql> select email,passwd from EmailUser where email = '12ae56789f1e4c8d8e1c31415867317c@auth.local';
+---------------------------------------------+------- +
| email | passwd |
+---------------------------------------------+--------+
| 12ae56789f1e4c8d8e1c31415867317c@auth.local | ! |
+---------------------------------------------+--------+
mysql> select username,provider,uid from social_auth_usersocialauth where username = '12ae56789f1e4c8d8e1c31415867317c@auth.local';
+---------------------------------------------+----------------+---------+
| username | provider | uid |
+---------------------------------------------+----------------+---------+
| 12ae56789f1e4c8d8e1c31415867317c@auth.local | authentik-saml | HR12345 |
+---------------------------------------------+----------------+---------+
```
## Migrating from one external authentication to another
First configure the two external authentications and test them with a dummy user. Then, to migrate all the existing users you only need to make changes to the `social_auth_usersocialauth` table. No entries need to be deleted or created. You only need to modify the existing ones. The `xxx@auth.local` remains the same, you only need to replace the `provider` and the `uid`.
## Migrating from external authentication to local user database
First, delete the entry in the `social_auth_usersocialauth` table that belongs to the particular user.
Then you can reset the user's password, e.g. via the web interface. The user will be assigned a local password and from now on the authentication against the local database of SeaTable will be done.
## Use LDAP and SAML together
Using SAML for authentication together with LDAP for synchronization is not a migration between authentication types but a permanent combined setup, available since SeaTable 3.5. It is enabled with `LDAP_SAML_USE_SAME_UID` and described in detail under [LDAP › LDAP and SAML](./ldap.md#ldap-and-saml).
---
## Configuration
Source: https://admin.seatable.com/configuration/overview/
# Overview
SeaTable supports two configuration mechanisms:
- Environment Variables
- Configuration Files
Environment variables can be used for the initial deployment and adjustment of the most important settings.
The following pages denote the reference for the configuration file for each system component.
# List of Available Environment Variables
SeaTable supports environment variables for initial deployment and configuration of some settings. This is the complete list of supported settings. With every version, new variables will be added.
Please note that this page only denotes environment variables used by SeaTable and its core components.
Since these variables are already defined inside the `seatable-server.yml` file that you have downloaded during the [installation process](../installation/basic-setup.md),
it is sufficient to set/modify these variables directly inside your `.env` file. There's no need to modify the `*.yml` files in order to adjust these settings.
```ini
# components to be used
COMPOSE_FILE='caddy.yml,seatable-server.yml' # (1)!
COMPOSE_PATH_SEPARATOR=','
# system settings
TIME_ZONE='Europe/Berlin' # (2)!
# seatable server base url
SEATABLE_SERVER_HOSTNAME='seatable.example.com' # (3)!
SEATABLE_SERVER_PROTOCOL='https' # (4)!
# initial web admin
SEATABLE_ADMIN_EMAIL='me@example.com' # (5)!
SEATABLE_ADMIN_PASSWORD='topsecret' # (6)!
# database
MARIADB_HOST='mariadb'
MARIADB_PORT='3306'
MARIADB_PASSWORD='topsecret' # (7)!
# Redis
REDIS_HOST='redis'
REDIS_PORT='6379'
REDIS_PASSWORD='topsecret'
JWT_PRIVATE_KEY='topsecret' # (8)!
SECRET_KEY='anothertopsecret' # (15)!
# SeaDoc
ENABLE_SEADOC='false'
SEADOC_PORT=''
# Python-Pipeline
PYTHON_SCHEDULER_URL='http://python-scheduler' # (13)!
PYTHON_SCHEDULER_AUTH_TOKEN='topsecret'
# SeaTable AI
ENABLE_SEATABLE_AI='false' # (14)!
INNER_SEATABLE_AI_SERVER_URL='http://seatable-ai:8888'
# E-Mail
SEATABLE_EMAIL_USE_TLS= # (12)!
SEATABLE_EMAIL_USE_SSL=
SEATABLE_EMAIL_HOST=
SEATABLE_EMAIL_HOST_USER=
SEATABLE_EMAIL_HOST_PASSWORD=
SEATABLE_EMAIL_PORT=
SEATABLE_DEFAULT_FROM_EMAIL=
SEATABLE_SERVER_EMAIL=
# Templates
SEATABLE_SHOW_TEMPLATES_LINK= # (9)!
SEATABLE_TEMPLATE_BASE_API_TOKEN=
SEATABLE_TEMPLATE_TABLE_NAME=
SEATABLE_ENABLE_CREATE_BASE_FROM_TEMPLATE=
# Logging
LOG_LEVEL=INFO # (10)!
# Docker Images
# You can use these variables to override the default images
SEATABLE_IMAGE=
SEATABLE_DB_IMAGE=
SEATABLE_REDIS_IMAGE=
IMAGE_CADDY=
# Miscellaneous
SEATABLE_HELP_LINK=https://seatable.com/help/ # (11)!
```
1. COMPOSE_FILE is a comma separated list of files **without spaces**. This list defines which components should run on this server.
2. Get a [list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) from Wikipedia.
3. Select your domain or subdomain that points to your Server (without https://). You have to set an A-Record or CNAME pointing to your IP.
4. Available options are `http` and `https`. Default value is `https`.
5. Email address of an initial admin user. Is only used during the first startup.
6. Password of an initial admin user. Is only used during the first startup.
7. Password for the root user for the MariaDB databases.
8. This private key is used to sign JWTs in SeaTable.
9. Please refer to [Templates](../customization/templates.md) for more information.
10. Allowed values are `DEBUG`, `INFO`, `WARNING`, `ERROR` and `CRITICAL`.
11. Please refer to [Manual Link](../customization/manual-in-nav.md) for more information.
12. Please refer to [Email Sending](./sending-email.md) for more information.
13. Please refer to [Python Pipeline](../installation/components/python-pipeline.md) for more information.
14. Please refer to [SeaTable AI](../installation/components/seatable-ai.md) for more information.
15. This secret key is used by the Django framework, which [`dtable-web`](../configuration/components/dtable-web.md) is based on.
---
Source: https://admin.seatable.com/configuration/customizations/
# Customizations
This page describes how administrators can customize the configuration of a given SeaTable installation while ensuring that future upgrades stay seamless.
## Context
The `.yml` files included in the artifact that is downloaded during the installation process already contain `environment:` blocks for the most important configuration settings.
These are listed [here](./overview.md#list-of-available-environment-variables).
If you need to modify any of these settings, it is sufficient to set/modify these variables directly inside your `.env` file.
There's no need to modify the `.yml` files in order to adjust these settings.
The `.yml` files included in the release artifact should **never** be modified since any changes made will be overwritten when following the [upgrade guide](../upgrade/upgrade-manual.md).
This is caused by the fact that the `.yml` files in your `/opt/seatable-compose` directory are essentially replaced by the `.yml` files from the release artifact of the SeaTable version that you're upgrading to.
## Mechanism
In order to configure additional settings that are not listed on the [overview page](./overview.md#list-of-available-environment-variables), you can (and should) create an additional `custom-seatable-server.yml` file that only contains the customizations that are relevant to your installation.
This has numerous benefits:
- This file is not overwritten during the upgrade process
- You do not introduce redundancy (i.e. that would be caused by copying the existing `seatable-server.yml` with all of its configuration settings)
- All of the customizations made are easily visible inside a single file
Simply follow the steps below:
### Step 1
Create `custom-seatable-server.yml` inside `/opt/seatable-compose` on the host.
The most minimal version of this file looks like this:
```yaml
services:
seatable-server:
```
### Step 2
Add `custom-seatable-server.yml` to the `COMPOSE_FILE` variable inside your `.env` file.
**Example:**
A minimal SeaTable installation contains the following line inside the `.env` file (located at `/opt/seatable-compose/.env`):
```ini
COMPOSE_FILE='caddy.yml,seatable-server.yml'
```
Now simpli add `custom-seatable-server.yml` to the list of filenames that should be merged by Docker Compose.
Additional filenames should be separated by a comma.
```ini
COMPOSE_FILE='caddy.yml,seatable-server.yml,custom-seatable-server.yml'
```
### Step 3
Apply the changes by running the following command inside a terminal:
```bash
cd /opt/seatable-compose
docker compose up -d
```
Docker Compose will merge all of the files specified inside the `COMPOSE_FILE` variable and restart all services whose configuration has changed.
This has an additional advantage: If a service's definition has not changed, it won't be unnecessarily restarted.
## Examples
### Adding an Environment Variable
If you need to configure an additional environment variable that is not included in `seatable-server.yml` by default, you can achieve this by adding the following block inside `custom-seatable-server.yml`:
```yaml
services:
seatable-server:
environment:
- API_GATEWAY_BASE_API_LIMIT_PER_MINUTE=1000
```
### Adding a Volume Mount
If you need to mount an additional file/directory (e.g. a custom NGINX config file) into the `seatable-server` container, you can achieve this by adding the following block inside `custom-seatable-server.yml`:
```yaml
services:
seatable-server:
volumes:
- ./custom-seatable-nginx.conf:/etc/nginx/sites-enabled/default
```
## Troubleshooting
If the merging does not work as expected, you can use `docker compose config` to print the result of the internal merging to the console.
Since this can cause quite a lot of output depending on the number of installed components, you can dump this into a file instead and open this inside a text editor:
```bash
docker compose config > /tmp/seatable-compose-config.yml
```
**Note:** `/tmp/seatable-compose-config.yml` will contain secret values since the `docker compose config` command prints the result of the configuration merging algorithm **after** all variables have been interpolated.
## Additional Resources
You can read more about the way multiple configuration files are merged together in the [Compose file reference](https://docs.docker.com/reference/compose-file/merge/).
---
## Components
Source: https://admin.seatable.com/configuration/components/dtable-api-gateway/
# Configuration of api-gateway
This is a cheat sheet for the possible configuration options of the [api-gateway](../../introduction/architecture.md#api-gateway).
It contains all possible settings that can be configured as well as their default values.
The default values provided here are best-effort (not built automatically). They will be used if no value is defined at all.
??? tip "Configuration changes require a restart"
New configuration options will only apply after a restart of SeaTable.
## Environment Variables
This section lists the environment variables read by the [api-gateway](../../introduction/architecture.md#api-gateway).
Please read our guide that explains how you can [customize the configuration](../customizations.md) of your SeaTable instance before you proceed.
### General
| Environment Variable | Description | Default |
| --------------------------------------- | --------------------------------------------------- | ------- |
| `API_GATEWAY_HOST` | The address the api-gateway listens on. | 0.0.0.0 |
| `API_GATEWAY_PORT` | The port the api-gateway listens on. | 7780 |
| `API_GATEWAY_MAX_BASE_CACHE_SIZE` | Maximum base cache size in MB. | 1024 |
| `API_GATEWAY_BASE_API_LIMIT_PER_MINUTE` | Limits the number of API calls per base per minute. | 500 |
### dtable-db
| Environment Variable | Description | Default |
| --------------------- | ------------------------------ | --------------------- |
| `INNER_DTABLE_DB_URL` | URL of the dtable-db instance. | http://127.0.0.1:7777 |
### dtable-server
| Environment Variable | Description | Default |
| ------------------------- | ---------------------------------- | --------------------- |
| `INNER_DTABLE_SERVER_URL` | URL of the dtable-server instance. | http://127.0.0.1:5000 |
### Metrics
| Environment Variable | Description | Default |
| --------------------------------------- | -------------------------------------------------------------------- | ------- |
| `API_GATEWAY_METRICS_ENABLE_BASIC_AUTH` | Whether basic authentication is enabled for the `/metrics` endpoint. | false |
| `API_GATEWAY_METRICS_USERNAME` | Username for basic authentication for the `/metrics` endpoint. | |
| `API_GATEWAY_METRICS_PASSWORD` | Password for basic authentication for the `/metrics` endpoint. | |
### Access Logs
| Environment Variable | Description | Default |
| --------------------------------------------- | ---------------------------------------------------------------------------------------- | ------- |
| `API_GATEWAY_ENABLE_ACCESS_LOG` | Whether the api-gateway logs information about incoming HTTP requests to a Redis stream. | false |
| `API_GATEWAY_ACCESS_LOG_REDIS_STREAM_KEY` | Key of the Redis stream that will contain access log entries. | |
| `API_GATEWAY_ACCESS_LOG_REDIS_STREAM_MAX_LEN` | Maximum length of the Redis stream. | 100000 |
## Configuration File (Legacy)
`dtable-api-gateway.conf` will not be read anymore after upgrading from v6.1 to v6.2.
Please migrate any custom settings to the respective [environment variables](#environment-variables).
The following section describes the structure and possible configuration values of the configuration file `dtable-api-gateway.conf`.
??? abstract "Notes about the configuration file format"
The configuration file uses the **INI format**, which is a simple text-based format for storing configuration data. It consists of sections (denoted by square brackets, e.g., [general]) and key-value pairs.
Comments in the configuration file start with the hash symbol `#` and extend to the end of the line.
When dealing with special characters like single quotes `'`, double quotes `"` or the hash symbol `#`, it's generally best to enclose the value in double quotes.
**Example Configuration**
SeaTable does not create the `dtable-api-gateway.conf` file by default. The `api-gateway` will use the default configuration values if the file does not exist.
### `[general]`
This section contains general settings about api-gateway service.
| Parameter | Description | Default |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- |
| `host` | The address api-gateway listens on. Defaults to localhost. | localhost |
| `port` | The port api-gateway listens on. | 7780 |
| `log_dir` | Location for the api-gateway logs in the container. | |
| `log_level` | Only log messages with level priority higher than this will be logged. Supported levels are "debug", "info", "warn", "error", with ascending priority. | info |
| `base_api_limit_per_minute` | Limits the number of API calls per base per minute. | 500 |
| `max_base_cache_size` | Maximum base cache size in MB. | 1024 |
### `[cluster]`
This section contains settings about api-gateway working with dtable-server or dtable-db cluster.
| Parameter | Description | Default |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `etcd_endpoints` | The address of the etcd, which should be same etcd with the dtable-server or dtable-db cluster. It's required if you enable dtable-server cluster or dtable-db cluster. It supports setting up multiple etcd endpoints like: 127.0.0.1:2379,127.0.0.1:2380 | 127.0.0.1:2379 |
### `[dtable-db]`
This section contains settings about api-gateway working with dtable-db.
| Parameter | Description | Default |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `cluster_mode` | Indicates whether dtable-db is running in cluster mode. Can be `true` or `false`. | `false` |
| `inner_dtable_db_url` | URL of the dtable-db instance. It's required if `cluster_mode` is set to `false`. You should not set it if `cluster_mode` is set to `true`. | http://127.0.0.1:7777 |
### `[dtable-server]`
This section contains settings about api-gateway working with dtable-server.
| Parameter | Description | Default |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `cluster_mode` | Indicates whether dtable-server is running in cluster mode. Can be `true` or `false`. | `false` |
| `inner_dtable_server_url` | URL of the dtable-server instance. It's required if `cluster_mode` is set to `false`. You should not set it if `cluster_mode` is set to `true`. | http://127.0.0.1:5000 |
## Deprecated or removed options
### `[dtable-db]`
- `server_address`: This option has been renamed to `inner_dtable_db_url` in v6.1 for consistency reasons. `server_address` is still read as of v6.1.
### `[dtable-server]`
- `server_address`: This option has been renamed to `inner_dtable_server_url` in v6.1 for consistency reasons. `server_address` is still read as of v6.1.
---
Source: https://admin.seatable.com/configuration/components/dtable-db/
# Configuration of dtable-db
This is a cheat sheet for the possible configuration options of [dtable-db](../../introduction/architecture.md#dtable-db).
It contains all possible settings that can be configured as well as their default values.
The default values provided here are best-effort (not built automatically). They will be used if no value is defined at all.
??? tip "Configuration changes require a restart"
New configuration options will only apply after a restart of SeaTable.
## Environment Variables
This section lists the environment variables read by [dtable-db](../../introduction/architecture.md#dtable-db).
Please read our guide that explains how you can [customize the configuration](../customizations.md) of your SeaTable instance before you proceed.
### General
| Environment Variable | Description | Default |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `DTABLE_DB_HOST` | The address dtable-db listens on. | 0.0.0.0 |
| `DTABLE_DB_PORT` | The port dtable-db listens on. | 7777 |
| `DTABLE_DB_SLOW_QUERY_THRESHOLD` | If the processing time exceeds this threshold, a slow log will be recorded in addition to the normal log. Unit is in milliseconds. | 1000 |
| `DTABLE_DB_ROW_UPDATE_LIMIT` | Sets the rate or row updates, deletes, and inserts per second and per base. | 5000 |
| `DTABLE_DB_GLOBAL_ROW_UPDATE_LIMIT` | Sets the global rate of row updates, deletes, and inserts per minute, affecting SQL and API operations. | 30000 |
| `DTABLE_DB_QUERY_PER_MINUTE_LIMIT` | Sets the total max. of API calls per minute for the entire system. The default is suitable for most cases. | 50000 |
### Storage
These settings define where the database files for bases with activated big data backend are stored and when old data is cleaned:
| Environment Variable | Description | Default |
| ------------------------------ | ------------------------------------------------------------- | --------------------- |
| `DTABLE_DB_DATA_DIR` | Location of the data directory inside the container. | /opt/seatable/db-data |
| `DTABLE_DB_STORAGE_CLEANUP_AT` | The execution time of clean up deleted data. Format is hh:mm. | 00:00 |
### DTable Cache
| Environment Variable | Description | Default |
| ---------------------------- | ---------------------------------- | --------------------- |
| `INNER_DTABLE_SERVER_URL` | URL of the dtable-server instance. | http://127.0.0.1:5000 |
| `DTABLE_DB_TOTAL_CACHE_SIZE` | The base cache size in MB. | 2000 |
### SQL
General configuration options of the output of the SQL endpoint:
| Environment Variable | Description | Default |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ------- |
| `DTABLE_DB_SQL_DEFAULT_RESULT_ROWS` | Maximal number of rows returned by a query if there's no `LIMIT` specified. | 100 |
| `DTABLE_DB_SQL_RESULT_ROWS_HARD_LIMIT` | Maximal number of rows returned in one query (system wide). Overrides any larger `LIMIT` value in a query. | 10000 |
| `DTABLE_DB_SQL_EXEC_COST_HARD_LIMIT` | Maximal execution cost of a query. If the estimated cost of a query exceeds this limit, the query is rejected. | 5000000 |
### Backup
These settings allow configuring how data stored inside the big data backend is backed up:
| Environment Variable | Description | Default |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `DTABLE_DB_BACKUP_AT` | The execution time of backup. Format is `hh:mm`. | 02:00 |
| `DTABLE_DB_BACKUP_KEEP_NUM` | The number of backups that will be kept, oldest backups will be removed. | 3 |
| `DTABLE_DB_BACKUP_KEEP_DAYS` | Specifies the retention period for backups in days. Older backups are deleted. Overrides `DTABLE_DB_BACKUP_KEEP_NUM` if set; otherwise, `DTABLE_DB_BACKUP_KEEP_NUM` is used. | 0 |
| `DTABLE_DB_BACKUP_KEEP_FREQUENCY_DAYS` | Specifies daily backup period. After this, only one backup per month is kept. Requires `DTABLE_DB_BACKUP_KEEP_DAYS` to be set and > `DTABLE_DB_BACKUP_KEEP_FREQUENCY_DAYS`. | 0 |
SeaTable offers two backup approaches:
- The first uses `DTABLE_DB_BACKUP_KEEP_NUM`, creating daily backups whenever changes were made and retaining a fixed number of the most recent ones, deleting the oldest when the limit is reached. Note that no new backup will be created if no changes were made to a base. This is the default option.
- The second approach, using `DTABLE_DB_BACKUP_KEEP_DAYS` and `DTABLE_DB_BACKUP_KEEP_FREQUENCY_DAYS`, offers a tiered retention strategy.
It creates daily backups for the recent period specified by `DTABLE_DB_BACKUP_KEEP_FREQUENCY_DAYS`, then switches to monthly backups for the older period.
This method provides detailed recent backups and efficient long-term storage, balancing data granularity with space conservation.
For example, setting `DTABLE_DB_BACKUP_KEEP_DAYS=180` and `DTABLE_DB_BACKUP_KEEP_FREQUENCY_DAYS=7` would keep daily backups for the past week, then monthly backups for the past six months (except for the past week).
The URL for `dtable-storage-server` is no longer configurable. As a consequence, `dtable-storage-server` must always run inside the same container as `dtable-db`.
This only matters in case SeaTable is deployed inside a cluster/as a distributed system.
### Metrics
| Environment Variable | Description | Default |
| ------------------------------------- | -------------------------------------------------------------------- | ------- |
| `DTABLE_DB_METRICS_ENABLE_BASIC_AUTH` | Whether basic authentication is enabled for the `/metrics` endpoint. | false |
| `DTABLE_DB_METRICS_USERNAME` | Username for basic authentication for the `/metrics` endpoint. | |
| `DTABLE_DB_METRICS_PASSWORD` | Password for basic authentication for the `/metrics` endpoint. | |
## Configuration File (Legacy)
`dtable-db.conf` will not be read anymore after upgrading from v6.1 to v6.2.
Please migrate any custom settings to the respective [environment variables](#environment-variables).
??? abstract "Notes about the configuration file format"
The configuration file uses the **INI format**, which is a simple text-based format for storing configuration data. It consists of sections (denoted by square brackets, e.g., [general]) and key-value pairs.
Comments in the configuration file start with the hash symbol `#` and extend to the end of the line.
When dealing with special characters like single quotes `'`, double quotes `"` or the hash symbol `#`, it's generally best to enclose the value in double quotes.
The following options are grouped by their sections.
**Example Configuration**
This is a typical configuration file, created automatically on the first startup by SeaTable.
```ini
[general]
host = 127.0.0.1
port = 7777
log_dir = /opt/seatable/logs
[storage]
data_dir = /opt/seatable/db-data
[dtable cache]
dtable_server_url = "http://127.0.0.1:5000"
[backup]
dtable_storage_server_url = "http://127.0.0.1:6666"
keep_backup_num = 3
```
### `[general]`
This section contains general settings about `dtable-db` service.
| Parameter | Description | Default |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ |
| `host` | The address `dtable-db` listens on. | 0.0.0.0 |
| `port` | The port `dtable-db` listens on. | 7777 |
| `log_dir` | Location for the `dtable-db` logs in the container. | /opt/seatable/logs |
| `log_level` | Only log messages with level priority higher than this will be logged. Supported levels are "debug", "info", "warn", "error", with ascending priority. | info |
| `slow_query_threshold` | If the processing time exceeds this threshold, a slow log will be recorded in addition to the normal log. Unit is in milliseconds. | 1000 |
| `query_per_minute_limit` | Sets the total max. of API calls per minute for the entire system. The default is suitable for most cases. | 50000 |
Please use the following parameters only in very special occasions. In most cases you should use the default, which means no limitation.
| Parameter | Description | Default |
| ------------------------- | ------------------------------------------------------------------------------------------------------- | ------- |
| `global_row_update_limit` | Sets the global rate of row updates, deletes, and inserts per second, affecting SQL and API operations. | 0 |
| `row_update_limit` | Sets the rate or row updates, deletes, and inserts per second and per base. | 0 |
### `[storage]`
This sections defines where the database files for bases with activated big data backend are stored and when old data is cleaned.
| Parameter | Description | Default |
| ------------ | ------------------------------------------------------------------------------ | --------------------- |
| `data_dir` | Location of the data directory in the container. You must specify this option. | /opt/seatable/db-data |
| `cleanup_at` | The execution time of clean up deleted data. Format is `hh:mm`. | 00:00 |
### `[dtable cache]`
This sections contains options for caching bases from dtable-server.
| Parameter | Description | Default |
| ------------------------- | ------------------------------------------------------------------------------------------ | --------------------- |
| `inner_dtable_server_url` | local address for dtable-server. You must specify this option. | http://127.0.0.1:5000 |
| `total_cache_size` | The base cache size in MB. Default was increased from 500 (MB) to 2000 (MB) in version 4.4 | 2000 |
### `[SQL]`
General configuration options of the output of the SQL endpoint.
| Parameter | Description | Default |
| ------------------------ | -------------------------------------------------------------------------------------------------------------- | ------- |
| `default_result_rows` | Maximal number of rows returned in one query, if `LIMIT` syntax is not used. | 100 |
| `result_rows_hard_limit` | Maximal number of rows returned in one query (system wide). Overrides any larger `LIMIT` value in a query | 10000 |
| `exec_cost_hard_limit` | Maximal execution cost of a query. If the estimated cost of a query exceeds this limit, the query is rejected. | 5000000 |
### `[backup]`
Section `[backup]` contains options to configure backup functions for big data backend.
| Parameter | Description | Default |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `dtable_storage_server_url` | The URL of dtable storage server. Required to enable automatic backup. | http://127.0.0.1:6666 |
| `backup_at` | The execution time of backup. Format is like `12:30`. It is mutual exclusion with `backup_interval`. | 02:00 |
| `keep_backup_num` | The number of backups that will be kept, oldest backups will be removed. | 3 |
| `keep_days` | Specifies the retention period for backups in days. Older backups are deleted. Overrides `keep_backup_num` if set; otherwise, `keep_backup_num` is used. | |
| `keep_frequency_days` | Specifies daily backup period. After this, only one backup per month is kept. Requires `keep_days` to be set and > `keep_frequency_days`. | |
Since version 5.2 SeaTable offers two backup approaches:
- The first uses `keep_backup_num`, creating daily backups whenever changes were made and retaining a fixed number of the most recent ones, deleting the oldest when the limit is reached. Note that no new backup will be created if no changes were made to a base. This is the default option.
- The second approach, using `keep_days` and `keep_frequency_days`, offers a tiered retention strategy. It creates daily backups for the recent period specified by `keep_frequency_days`, then switches to monthly backups for the older period. This method provides detailed recent backups and efficient long-term storage, balancing data granularity with space conservation. For example, setting `keep_days = 180` and `keep_frequency_days = 7` would keep daily backups for the past week, then monthly backups for the past six months (except for the past week).
## Deprecated or removed options
### `[database]`
??? note "[database] is not necessary anymore"
Since version 5.3, `dtable-db` reads database connection settings from [environment variables](/configuration/overview).
From version 2.7 to version 5.2, `dtable-db` used the database settings in `dtable_server_config.json`.
The section `[database]` contained options for accessing the MySQL database used by dtable-server.
- `host`: Address of database. You must provide this option.
- `port`: Port of database. Defaults to 3306.
- `user`: Username for login to the database. You must provide this option.
- `password`: Password for the database user. You must provide this option.
- `db_name`: Database name used by dtable-server. You must provide this option.
### `[general]`
- `base_api_limit_per_day`: Limits the number of API calls per base per day. -1 means no limit.
### `[dtable cache]`
- `private_key`: Must be the same value like `DTABLE_PRIVATE_KEY` in `dtable_web_settings.py`. Only necessary if your version is before "Enterprise edition 3.5.5". If your version is newer the value is read from `dtable_server_config.json`.
- `clean_cache_interval`: Interval between cache cleaning. Unit is in seconds. Defaults to 300. This option is removed in "Enterprise edition 4.4.0". Since 4.4.0 a real-time eviction mechanism replaced regular cache cleanup mechanism.
- `dtable_server_url`: This option has been renamed to `inner_dtable_server_url` in v6.1 for consistency reasons. `dtable_server_url` is still read as of v6.1.
### `[SQL]`
- `group_by_stmt_limit`: Maximal number of concurrent `group by` requests. If the number of `group by` requests exceeds this limit, new `group by` queries will wait in a queue. Default is 2. This option is removed in version 5.1.0. This option was only relevant when querying bases with big-data. In 5.1.0 version `group by` queries can be handled by a new OLAP engine, which is much more efficient. So this option is no longer necessary.
### `[backup]`
- `backup_interval`: The interval between each backup. Unit is in seconds. The default value is 86400 (=24 hours). You can not define `backup_interval` and `backup_at` at the same time. This option is deprecated since version 5.2. It's suggested to backup your bases once per day with the `backup_at` option.
---
Source: https://admin.seatable.com/configuration/components/dtable-events/
# Configuration of dtable-events
This is a cheat sheet for the possible configuration options of [dtable-events](../../introduction/architecture.md#dtable-events).
It contains all possible settings that can be configured as well as their default values.
The default values provided here are best-effort (not built automatically). They will be used if no value is defined at all.
??? tip "Configuration changes require a restart"
New configuration options will only apply after a restart of SeaTable.
## Environment Variables
This section lists the environment variables read by [dtable-events](../../introduction/architecture.md#dtable-events).
Please read our guide that explains how you can [customize the configuration](../customizations.md) of your SeaTable instance before you proceed.
### Automations
| Environment Variable | Description | Default |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| `AUTOMATION_WORKERS` | Configures the number of worker threads used to process automation rule events | 5 |
| `AUTOMATION_RATE_LIMIT_WINDOW_SECS` | The time window (in seconds) used to calculate automation rate limits | 300 |
| `AUTOMATION_RATE_LIMIT_PERCENT` | The maximum percentage of total available automation capacity a single team can use within the defined time window. Defaults to 25%. | 0.25 |
By default, these settings will limit a single team to 25% of the available automation running time (calculated by `AUTOMATION_WORKERS * AUTOMATION_RATE_LIMIT_WINDOW_SECS`) within 5 minutes.
### Common Dataset Syncer
SeaTable runs every hour this event to check for pending dataset syncs. The job processes datasets that need syncing based on their interval (per_day, per_hour) and validity.
| Environment Variable | Description | Default |
| ------------------------------- | --------------------------------------------- | ------- |
| `COMMON_DATASET_SYNCER_ENABLED` | Enables or disables the common dataset syncer | true |
### Database Cleanup
**Enabled** by default since v6.2.
This setting controls whether SeaTable runs automated database cleanup tasks at 00:30 every day.
Enabling this task ensures that your database stays lean and performs well. It also prevents the server from running out of disk space, since operation logs can take up quite a lot of space.
In addition, the retention periods for the different database tables can be customized.
Setting any value to `0` or `-1` causes the cleanup task to be skipped for the corresponding database table.
| Environment Variable | Description | Default |
| --------------------------------------------------- | -------------------------------------------------------------------------- | ------- |
| `CLEAN_DB_ENABLED` | Enables the automated database cleanup tasks | true |
| `CLEAN_DB_KEEP_DTABLE_SNAPSHOT_DAYS` | Retention period for snapshot entries in the database (in days) | 365 |
| `CLEAN_DB_KEEP_ACTIVITIES_DAYS` | Retention period for activities (in days) | 30 |
| `CLEAN_DB_KEEP_OPERATION_LOG_DAYS` | Retention period for operation log entries (in days) | 14 |
| `CLEAN_DB_KEEP_DELETE_OPERATION_LOG_DAYS` | Retention period for delete operations in the operation log (in days) | 30 |
| `CLEAN_DB_KEEP_DTABLE_DB_OP_LOG_DAYS` | Retention period for operation log entries inserted by dtable-db (in days) | 30 |
| `CLEAN_DB_KEEP_NOTIFICATIONS_USERNOTIFICATION_DAYS` | Retention period for user notifications (in days) | 30 |
| `CLEAN_DB_KEEP_DTABLE_NOTIFICATIONS_DAYS` | Retention period for base notifications (in days) | 30 |
| `CLEAN_DB_KEEP_SESSION_LOG_DAYS` | Retention period for session log entries (in days) | 30 |
| `CLEAN_DB_KEEP_AUTO_RULES_TASK_LOG_DAYS` | Retention period for automation rule logs (in days) | 30 |
| `CLEAN_DB_KEEP_USER_ACTIVITY_STATISTICS_DAYS` | Retention period for user activity statistics (in days) | 0 |
| `CLEAN_DB_KEEP_DTABLE_APP_PAGES_OPERATION_LOG_DAYS` | Retention period for app pages operation log entries (in days) | 14 |
| `CLEAN_DB_KEEP_EMAIL_SENDING_LOG_DAYS` | Retention period for log entries regarding sent emails (in days) | 30 |
| `CLEAN_DB_KEEP_SYSADMIN_EXTRA_USERLOGINLOG_DAYS` | Retention period for login logs (in days) | 30 |
### Email Notices
SeaTable runs this task every hour to send base email notifications for base updates to the users. It also generates the log file `dtable_updates_sender.log`.
| Environment Variable | Description | Default |
| ---------------------- | ------------------------------------------------------------ | ------- |
| `EMAIL_SENDER_ENABLED` | Enables or disables the email notifications for base updates | true |
### Email Syncer
SeaTable runs this event at the 30th minute of every hour. The job processes email sync tasks defined in a base by the user.
| Environment Variable | Description | Default |
| -------------------------- | ---------------------------------------------------------------- | ------- |
| `EMAIL_SYNCER_ENABLED` | Enables or disables the email syncer | true |
| `EMAIL_SYNCER_MAX_WORKERS` | Maximum number of worker threads for processing email sync tasks | 5 |
### LDAP Sync
SeaTable is able to sync LDAP accounts. This requires additional settings in `dtable_web_settings.py`. Please refer to [LDAP Authentication](../authentication/ldap.md).
| Environment Variable | Description | Default |
| -------------------- | ---------------------------------------------------------------------------------------- | ------- |
| `LDAP_SYNC_ENABLED` | Enables or disables the LDAP sync | false |
| `LDAP_SYNC_INTERVAL` | Specifies the interval at which the LDAP synchronization process should run (in seconds) | 3600 |
### PDF Generation
| Environment Variable | Description | Default |
| ---------------------------------- | --------------------------------------------------------- | ------- |
| `CONVERT_PDF_BROWSERS` | Number of browser processes started to generate PDF files | 2 |
| `CONVERT_PDF_SESSIONS_PER_BROWSER` | Number of sessions per browser instance | 3 |
### Virus Scan
**Disabled** by default.
This section configures how files are scanned for viruses:
- Whether scanning is enabled
- The command used to scan files
- Return codes indicating infected or clean files
- Limits on file size and extensions to skip
- Concurrency settings
| Parameter | Description | Default |
| ---------------------------- | ---------------------------------------------------------------- | --------------------------------------------------------- |
| `VIRUS_SCAN_ENABLED` | Enables or disables virus scanning | false |
| `VIRUS_SCAN_SCAN_COMMAND` | Command used for virus scanning (e.g. `clamscan`) | |
| `VIRUS_SCAN_VIRUS_CODE` | Return codes indicating a file is infected (e.g. 0) | |
| `VIRUS_SCAN_NONVIRUS_CODE` | Return codes indicating a file is clean (e.g. 1) | |
| `VIRUS_SCAN_SCAN_INTERVAL` | The interval at which the virus scan runs (in minutes) | 60 |
| `VIRUS_SCAN_SCAN_SIZE_LIMIT` | Maximum file size to scan (in MB); larger files are skipped | 20 |
| `VIRUS_SCAN_SCAN_SKIP_EXT` | Comma-separated list of file extensions to exclude from scanning | `.bmp,.gif,.ico,.png,.jpg,.mp3,.mp4,.wav,.avi,.rmvb,.mkv` |
| `VIRUS_SCAN_THREADS` | Number of threads for parallel scanning | 4 |
## Configuration File (Legacy)
`dtable-events.conf` will not be read anymore after upgrading from v6.1 to v6.2.
Please migrate any custom settings to the respective [environment variables](#environment-variables).
The following section describes the structure and possible configuration values of the configuration file `dtable-events.conf`.
??? abstract "Notes about the configuration file format"
The configuration file uses the **INI format**, which is a simple text-based format for storing configuration data. It consists of sections (denoted by square brackets, e.g., [general]) and key-value pairs.
Comments in the configuration file start with the hash symbol `#` and extend to the end of the line.
When dealing with special characters like single quotes `'`, double quotes `"` or the hash symbol `#`, it's generally best to enclose the value in double quotes.
`dtable-events` reads `dtable_web_settings.py` for internal URLs and various key settings. Ensure these configurations are correct.
Other configuration files are not used, if you run dtable-events separately.
Since SeaTable 5.3, by default, you can start the dtable-events service without adding any configurations to `dtable-events.conf`, as the key startup configurations (i.e. *MySQL* and *Redis*) are already configured in the environment variables by default (i.e., `.env`). On the other hand, you can also add other dtable-events service related configurations to `dtable-events.conf`, which mainly contains some sections and their options:
- Section names in `dtable-events.conf` compose of **uppercase** and **spaces** (such as `[COMMON DATASET SYNCER]`).
- Option names will be mainly **lowercase** with **underscores** (such as `per_update_auto_rule_workers`).
The following options are grouped by their sections.
**Example Configuration**
By default, `dtable-events.conf` will contain the following configuration after the first startup of SeaTable:
```ini
[CLEAN DB]
enabled = true
```
### `[DATABASE]`
??? success "Database can be configured in .env"
From SeaTable 5.3, you can specify the database configurations in [`.env`](../overview.md). There is no need to keep this configuration in your `dtable-events.conf`.
| Parameter | Description | Default |
| ---------- | ------------------------------------------------------------------------------------------------------- | ----------------- |
| `type` | The database connection type. Use `mysql` for MySQL and MariaDB (other databases are not yet supported) | mysql |
| `host` | MariaDB server address | mariadb |
| `port` | MariaDB server port | 3306 |
| `db_name` | Database name | dtable_db |
| `username` | MariaDB username | root |
| `password` | MariaDB password | `$DB_ROOT_PASSWD` |
### `[REDIS]`
??? success "Redis can be configured in .env"
From SeaTable 5.3, you can specify the redis configurations in [`.env`](../overview.md). There is no need to keep this configuration in your `dtable-events.conf`.
| Parameter | Description | Default |
| ---------- | --------------------- | ------- |
| `host` | Redis server address | redis |
| `port` | Redis server port | 6379 |
| `password` | Redis server password | |
### `[CLEAN DB]`
**disabled** by default.
This setting controls whether SeaTable runs automated database cleanup tasks at 00:30 every day.
Enabling this task ensures that your database stays lean and performs well. It also prevents the server from running out of disk space, since operation logs can take up quite a lot of space.
In addition, the retention periods for the different database tables can be customized.
Setting any value to `0` or `-1` causes the cleanup task to be skipped for the corresponding database table.
| Parameter | Description | Default |
| ------------------------------------------ | -------------------------------------------------------------------------- | ------- |
| `enabled` | Enables or disables the email notifications for base updates | false |
| `keep_dtable_snapshot_days` | Retention period for snapshot entries in the database (in days) | 365 |
| `keep_activities_days` | Retention period for activities (in days) | 30 |
| `keep_operation_log_days` | Retention period for operation log entries (in days) | 14 |
| `keep_delete_operation_log_days` | Retention period for delete operations in the operation log (in days) | 30 |
| `keep_dtable_db_op_log_days` | Retention period for operation log entries inserted by dtable-db (in days) | 30 |
| `keep_notifications_usernotification_days` | Retention period for user notifications (in days) | 30 |
| `keep_dtable_notifications_days` | Retention period for base notifications (in days) | 30 |
| `keep_session_log_days` | Retention period for session log entries (in days) | 30 |
| `keep_auto_rules_task_log_days` | Retention period for automation rule logs (in days) | 30 |
| `keep_user_activity_statistics_days` | Retention period for user activity statistics (in days) | 0 |
| `keep_dtable_app_pages_operation_log_days` | Retention period for app pages operation log entries (in days) | 14 |
### `[EMAIL SENDER]`
**enabled** by default.
SeaTable runs this task every hour to send base email notifications for base updates to the users. It also generates the log file `dtable_updates_sender.log`.
| Parameter | Description | Default |
| --------- | ------------------------------------------------------------ | ------- |
| `enabled` | Enables or disables the email notifications for base updates | true |
### `[COMMON DATASET SYNCER]`
**enabled** by default.
SeaTable runs every hour this event to check for pending dataset syncs. The job processes datasets that need syncing based on their interval (`per_day`, `per_hour`) and validity.
| Parameter | Description | Default |
| --------- | --------------------------------------------- | ------- |
| `enabled` | Enables or disables the common dataset syncer | true |
### `[EMAIL SYNCER]`
**enabled** by default.
SeaTable runs this event at the 30th minute of every hour. The job processes email sync tasks defined in a base by the user.
| Parameter | Description | Default |
| ------------- | ---------------------------------------------------------------- | ------- |
| `enabled` | Enables or disables the email syncer | true |
| `max_workers` | Maximum number of worker threads for processing email sync tasks | 5 |
### `[LDAP SYNC]`
**disabled** by default.
SeaTable could sync LDAP accounts, if activated. This requires additional settings in `dtable_web_settings.py`. Please refer to [LDAP Authentication](../authentication/ldap.md).
| Parameter | Description | Default |
| --------------- | --------------------------------------------------------------------------------------- | ------- |
| `enabled` | Enables or disables the ldap sync | false |
| `sync_interval` | Specifies the interval at which the LDAP synchronization process should run, in seconds | 3600 |
### `[VIRUS SCAN]`
**disabled** by default.
This section configures how files are scanned for viruses:
- Whether scanning is enabled (enabled)
- The command used to scan files (scan_command)
- Return codes indicating infected or clean files (virus_code, nonvirus_code)
- Limits on file size and extensions to skip (scan_size_limit, scan_skip_ext)
- Concurrency settings (threads)
| Parameter | Description | Default |
| ----------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `enabled` | Enables or disables virus scanning | false |
| `scan_command` | Command used for virus scanning (e.g., clamscan) | |
| `virus_code` | Return codes indicating a file is infected (e.g. 0) | |
| `nonvirus_code` | Return codes indicating a file is clean (e.g. 1) | |
| `scan_interval` | The interval at which the virus scan runs (in minutes) | 60 |
| `scan_size_limit` | Maximum file size to scan (in MB); larger files are skipped | 20 |
| `scan_skip_ext` | File extensions to exclude from scanning | ['.bmp', '.gif', '.ico', '.png', '.jpg', '.mp3', '.mp4', '.wav', '.avi', '.rmvb', '.mkv'] |
| `threads` | Number of threads for parallel scanning | 4 |
## Deprecated or removed options
### `[DATABASE]`
??? note "[DATABASE] is not necessary anymore"
Since version 5.3, `dtable-events` reads database settings from [environment variables](/configuration/overview).
The section `[DATABASE]` contained options for accessing the MySQL database used by `dtable-events`.
- `type`: Database connection type. Use `mysql` for MySQL and MariaDB. Other databases are not yet supported.
- `host`: Address of database. You must provide this option.
- `port`: Port of database. Defaults to 3306.
- `username`: Username for login to the database. You must provide this option.
- `password`: Password for the database user. You must provide this option.
- `db_name`: Database name used by `dtable-events`. You must provide this option.
### `[REDIS]`
??? note "[REDIS] is not necessary anymore"
Since version 5.3, `dtable-events` reads Redis connection settings from [environment variables](/configuration/overview).
The section `[REDIS]` used to contain the following options:
- `host`: Redis server address. Defaults to `redis`.
- `port`: Redis server port. Defaults to `6379`.
- `password`: Redis server password (optional).
### `[AUTOMATION]`
- `per_minute_trigger_limit`: This setting allowed an administrator to restrict the frequency of automation rule executions. It has been removed in SeaTable 5.3.
- `per_update_auto_rule_workers`: This setting allowed an administrator to configure the number of worker threads used to process automation rule events. It has been removed in SeaTable 6.1. You should use the environment variable `AUTOMATION_WORKERS` instead.
### `[ROWS COUNTER]`
This section used to contain a single setting called `enabled` that could be used to enable a periodic counter that counted the total number of rows of each team.
The section has been removed in SeaTable 5.3.
---
Source: https://admin.seatable.com/configuration/components/dtable-server/
# Configuration of dtable-server
This is a cheat sheet for the possible configuration options of [dtable-server](../../introduction/architecture.md#dtable-server).
It contains all possible settings that can be configured as well as their default values.
The default values provided here are best-effort (not built automatically). They will be used if no value is defined at all.
??? tip "Configuration changes require a restart"
New configuration options will only apply after a restart of SeaTable.
## Environment Variables
This section lists the environment variables read by [dtable-server](../../introduction/architecture.md#dtable-server).
Please read our guide that explains how you can [customize the configuration](../customizations.md) of your SeaTable instance before you proceed.
### Automations
| Environment Variable | Description | Default |
| --------------------------------------- | -------------------------------------------------------------------------- | ------- |
| `AUTOMATION_RATE_LIMIT_PER_BASE_MINUTE` | Limits the number of automations that can be triggered per base per minute | 1000 |
### Persistence
| Environment Variable | Description | Default |
| -------------------- | ----------------------------------------------------------------------- | ------- |
| `SAVE_INTERVAL` | Auto-save interval for modified bases, in milliseconds. (300000 = 5min) | 300000 |
### Service URLs
| Environment Variable | Description | Default |
| --------------------------------- | ---------------------- | ---------------------- |
| `INNER_DTABLE_WEB_SERVICE_URL` | dtable-web service URL | http://127.0.0.1:8000/ |
| `INNER_DTABLE_DB_URL` | dtable-db service URL | http://127.0.0.1:7777/ |
| `INNER_DTABLE_STORAGE_SERVER_URL` | dtable-db service URL | http://127.0.0.1:6666/ |
### Row Limits
| Environment Variable | Description | Default |
| --------------------- | ---------------------------------------------------------------------------------- | ------- |
| `BASE_WRITABLE_LIMIT` | Soft limit for rows in a base. Exceeding this shows an error in the web interface. | 100000 |
| `BASE_MAX_ROWS_LIMIT` | Hard limit for rows in a base. Server prevents any writes beyond this number. | 150000 |
### Base Size Limit
| Environment Variable | Description | Default |
| -------------------- | ------------------------------------------------------------------------ | ------- |
| `BASE_MAX_SIZE` | Maximum size of a base's JSON file (excluding assets and big data) in MB | 200 |
## Configuration File (Legacy)
`dtable_server_config.json` will not be read anymore after upgrading from v6.1 to v6.2.
Please migrate any custom settings to the respective [environment variables](#environment-variables).
The following section describes the structure and possible configuration values of the configuration file `dtable_server_config.json`.
??? abstract "Notes about the configuration file format"
The configuration file uses the **JSON format** (JavaScript Object Notation), which is a lightweight, text-based format for storing and transmitting structured data. It consists of key-value pairs and nested objects, represented by curly braces {}. Comments are not supported in JSON.
When dealing with special characters like single quotes ', double quotes ", or backslashes , JSON has specific escaping rules. Double quotes " are used to enclose strings, and special characters within strings should be escaped with a backslash.
JSON is strict about syntax, particularly with commas. Each key-value pair in an object must be separated by a comma, and there should be no trailing comma after the last key-value pair.
**Example configuration**
By default, `dtable_server_config.json` will be empty after the first startup of SeaTable:
```json
{}
```
### Redis
| Parameter | Description | Default |
| ----------------------------- | ---------------------------------------- | ------- |
| `enable_notification_publish` | Enable real-time notifications via Redis | false |
### Persistence
`dtable-server` keeps bases in memory. After a certain time, the bases are persisted to storage (via dtable-storage-server).
| Parameter | Description | Default |
| --------------- | ----------------------------------------------------------------------- | ------- |
| `save_interval` | Auto-save interval for modified bases, in milliseconds. (300000 = 5min) | 300000 |
### Service URLs
| Parameter | Description | Default |
| --------------------------- | ------------------------- | ---------------------- |
| `dtable_web_service_url` | dtable-web service URL | http://127.0.0.1:8000/ |
| `dtable_db_service_url` | dtable-db service URL | http://127.0.0.1:7777/ |
| `dtable_storage_server_url` | dtable-storage-server URL | http://127.0.0.1:6666/ |
??? warning "API-Gateway is not configurable"
API-Gateway URL is not configurable. It is always `dtable_web_service_url + api-gateway`.
### Row Limits
Please note that increasing this value requires corresponding updates in `dtable_web_settings.py`, as detailed [here](../base-rows-limit.md).
| Parameter | Description | Default |
| --------------------- | ---------------------------------------------------------------------------------- | ------- |
| `base_writable_limit` | Soft limit for rows in a base. Exceeding this shows an error in the web interface. | 100000 |
| `base_max_rows_limit` | Hard limit for rows in a base. Server prevents any writes beyond this number. | 150000 |
### Base Size Limit
| Parameter | Description | Default |
| --------------- | ------------------------------------------------------------------------- | ------- |
| `base_max_size` | Maximum size of a base's JSON file (excluding assets and big data) in MB. | 200 |
### Expert Configuration
It is not recommended to change these values
| Parameter | Description | Default |
| --------------------------- | -------------------------------------------------------------------------------------- | ------- |
| `worker_threads_num` | Number of worker threads serving list rows API (for custom shares or view shares only) | 2 |
| `worker_threads_rows_limit` | Maximum rows, returned in custom shares or view shares | 50000 |
| `rows_api_max_limit` | Maximum number of rows returned by calling list rows API in dtable-server | 1000 |
| `redirect_list_rows_api` | Redirect API requests to the API-Gateway. | false |
### Cluster Setup
For more information on setting up a SeaTable cluster, which is typically suitable for systems supporting hundreds of users, please contact us.
## Deprecated settings
### Automation Limits
The setting `per_minute_trigger_limit`, which allowed limiting the number of automations that could be triggered per base per minute, has been removed in v6.1.
You can use the environment variable `AUTOMATION_RATE_LIMIT_PER_BASE_MINUTE` instead if you want to modify the default setting.
### MariaDB Database Connection
`dtable-server` used to read the database connection settings from `dtable_server_config.json`.
Since version 5.3, `dtable-server` reads these settings from [environment variables](/configuration/overview) instead.
| Parameter | Description | Default |
| ---------- | ---------------------- | ----------------- |
| `host` | MariaDB server address | `$DB_HOST` |
| `user` | MariaDB username | root |
| `password` | MariaDB password | `$DB_ROOT_PASSWD` |
| `database` | Database name | dtable_db |
| `port` | MariaDB server port | 3306 |
### Redis Connection
`dtable-server` used to read the Redis connection settings from `dtable_server_config.json`.
Since version 5.3, `dtable-server` reads these settings from [environment variables](/configuration/overview) instead.
| Parameter | Description | Default |
| ----------------------------- | ---------------------------------------- | ------- |
| `redis_host` | Redis server address | redis |
| `redis_password` | Redis password (often empty) | |
| `redis_port` | Redis server port | 6379 |
| `enable_notification_publish` | Enable real-time notifications via Redis | false |
### Private Key
Starting with version 5.3, it is no longer required to provide `private_key` that is used to sign JWTs inside the configuration file.
`dtable-server` reads this value from the `JWT_PRIVATE_KEY` [environment variable](/configuration/overview) instead.
| Parameter | Description | Default |
| ------------- | ---------------------------------------------------------------------------------------------------- | ------- |
| `private_key` | Shared secret for dtable_web connection. Must match `DTABLE_PRIVATE_KEY` in `dtable_web_settings.py` | |
### API-Limits
The API limits mentioned are no longer applicable. Prior to SeaTable version 5.2, separate API limits existed for dtable-server and dtable-db. However, starting with version 5.2, API requests are now handled by the api-gateway, which enforces unified API limits across the platform.
| Parameter | Description | Default |
| --------------------- | -------------------------------------- | ------- |
| `api_req_max` | Max API calls to a base per minute. | 600 |
| `api_base_day_max` | Max API calls to a base per day. | 5000 |
| `rows_api_minute_max` | Max listing rows API calls per minute. | 100 |
| `rows_api_hour_max` | Max listing rows API calls per hour. | 6000 |
### Slave-Mode and Database-Split
These functions are deprecated and not maintained further.
---
Source: https://admin.seatable.com/configuration/components/dtable-storage-server/
# Configuration of dtable-storage-server
This is a cheat sheet for the possible configuration options of [dtable-storage-server](../../introduction/architecture.md#dtable-storage-server).
It contains all possible settings that can be configured as well as their default values.
The default values provided here are best-effort (not built automatically). They will be used if no value is defined at all.
??? tip "Configuration changes require a restart"
New configuration options will only apply after a restart of SeaTable.
## Environment Variables
This section lists the environment variables read by [dtable-storage-server](../../introduction/architecture.md#dtable-storage-server).
Please read our guide that explains how you can [customize the configuration](../customizations.md) of your SeaTable instance before you proceed.
### General
| Environment Variable | Description | Default |
| --------------------- | --------------------------------------------- | ------- |
| `STORAGE_SERVER_HOST` | The address dtable-storage-server listens on. | 0.0.0.0 |
| `STORAGE_SERVER_PORT` | The port dtable-storage-server listens on. | 6666 |
### Storage Backend
| Environment Variable | Description | Default |
| ----------------------------- | --------------------------------------------------------------- | ---------- |
| `STORAGE_SERVER_BACKEND_TYPE` | The type of storage backend. Options are `filesystem` and `s3`. | filesystem |
Depending on the chosen storage backend, there are additional settings:
#### Filesystem Backend
| Environment Variable | Description | Default |
| ------------------------ | -------------------------------- | -------------------------- |
| `STORAGE_SERVER_FS_PATH` | The filepath of storage backend. | /opt/seatable/storage-data |
#### S3 Backend
Please refer to the [S3 docs](../../installation/advanced/s3.md).
### Snapshots
| Environment Variable | Description | Default |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `STORAGE_SERVER_ENABLE_SNAPSHOT_CLEANUP` | Controls snapshot cleanup. Activate on only one node in multi-server setups. | true |
| `STORAGE_SERVER_SNAPSHOT_CLEANUP_AT` | Specifies the time when old snapshots are deleted. | 03:00 |
| `STORAGE_SERVER_SNAPSHOT_KEEP_DAYS` | Specifies the snapshot retention period in days. Older snapshots are deleted. | 180 |
| `STORAGE_SERVER_SNAPSHOT_KEEP_FREQUENCY_DAYS` | Specifies daily snapshot period for changed bases. After this, only one snapshot per month is kept. Default is 0 (always daily). Requires `STORAGE_SERVER_SNAPSHOT_KEEP_DAYS` to be set and > `STORAGE_SERVER_SNAPSHOT_KEEP_FREQUENCY_DAYS`. | 0 |
## Configuration File (Legacy)
`dtable-storage-server.conf` will not be read anymore after upgrading from v6.1 to v6.2.
Please migrate any custom settings to the respective [environment variables](#environment-variables).
??? abstract "Notes about the configuration file format"
The configuration file uses the **INI format**, which is a simple text-based format for storing configuration data. It consists of sections (denoted by square brackets, e.g., [general]) and key-value pairs.
Comments in the configuration file start with the hash symbol `#` and extend to the end of the line.
When dealing with special characters like single quotes `'`, double quotes `"` or the hash symbol `#`, it's generally best to enclose the value in double quotes.
The following options are grouped by their sections.
**Example Configuration**
This is a typical configuration file, created automatically on the first startup by SeaTable.
```ini
[general]
log_dir = /opt/seatable/logs
temp_file_dir = /tmp/tmp-storage-data
[storage backend]
type = filesystem
path = /opt/seatable/storage-data
[snapshot]
interval = 86400
keep_days = 180
```
### `[general]`
This section contains general settings about the `dtable-storage-server` service.
| Parameter | Description | Default |
| --------------- | -------------------------------------------------------------------------------------- | ----------------------------------- |
| `host` | The address `dtable-storage-server` listens on. | `127.0.0.1` |
| `port` | The port `dtable-storage-server` listens on. | `6666` |
| `log_dir` | The directory that dtable-storage-server writes logs to. | Directory of the configuration file |
| `temp_file_dir` | The directory that dtable-storage-server creates buffers in. This setting is required. | |
### `[storage backend]`
This section is used to configure the storage backend.
| Parameter | Description | Default |
| --------- | --------------------------------------------------------------- | ------------ |
| `type` | The type of storage backend. Options are `filesystem` and `s3`. | `filesystem` |
Depending on the chosen storage backend, there are additional settings:
#### Filesystem Storage Backend
| Parameter | Description | Default |
| --------- | -------------------------------- | ---------------------------- |
| `path` | The filepath of storage backend. | `/opt/seatable/storage-data` |
#### S3 Storage Backend
| Parameter | Description | Default |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `bucket` | The bucket name for the S3 backend. | |
| `key_id` | The access key id for the bucket. | |
| `key` | The secret access key for the bucket. | |
| `use_v4_signature` | Whether to use v4 signature. For a S3-compatible storage, it should be `false`. | |
| `aws_region` | The AWS region (only when v4 signature is used). | |
| `host` | The host address of S3 backend. Required for S3-compatible storage. Optional for AWS S3, but can be set to the endpoint you use. | |
| `path_style_request` | Whether to use path style requests. For a S3-compatible storage, it should be `true`. | |
| `use_https` | Whether to use https. | |
| `sse_c_key` | Use [server-side encryption with customer-provided keys](../../installation/advanced/s3-encryption.md) (SSE-C). This setting is optional. | |
### `[snapshot]`
| Parameter | Description | Default |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
| `interval` | The interval for generating snapshots of a base, if there are changes to the base. Unit is in seconds. | 86400 |
| `enable_cleanup` | Controls snapshot cleanup. Activate on only one node in multi-server setups. | true |
| `keep_days` | Specifies the snapshot retention period in days. Older snapshots are deleted. As of version 5.2, the default is 180 days; previously, it was unlimited (0). | 180 |
| `keep_frequency_days` | Specifies daily snapshot period for changed bases. After this, only one snapshot per month is kept. Default is 0 (always daily). Requires keep_days to be set and > `keep_frequency_days`. | 0 |
| `cleanup_at` | Specifies the time when old snapshots are deleted. | 03:00 |
By default, SeaTable creates daily snapshots for changed bases, deleting snapshots older than 180 days. The cleanup
**Since version 5.2**, SeaTable offers a tiered retention strategy for snapshots. This approach balances recent, detailed backups with efficient long-term storage.
For example, setting `keep_days = 180` and `keep_frequency_days = 7` would retain:
- Daily snapshots for the past week
- Monthly snapshots for the past six months, except for the past week.
#### Possible combinations of `keep_days` and `keep_frequency_days` for new tiered snapshot retention
| Condition | Action |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `keep_days = 0` | No snapshots are deleted, no matter of `keep_frequency_days`. |
| `keep_frequency_days = 0` and `keep_days > 0` | All snapshots older than `keep_days` are deleted. |
| `keep_frequency_days > 0` and `keep_days > 0` | Snapshots older than `keep_days` are deleted immediately, while snapshots older than `keep_frequency_days` but not exceeding `keep_days` are grouped by month to apply frequency-based cleaning logic. |
---
Source: https://admin.seatable.com/configuration/components/dtable-web/
# dtable web settings
You need to [restart SeaTable](../../maintenance/restart-seatable.md) so that your changes take effect.
You can also modify some of the config items as system administrator via web interface. These config items are saved in the database table (dtable_db/constance_config). The configuration in the database has a higher priority then the items in config file. If you want to disable settings via web interface, you can add `ENABLE_SETTINGS_VIA_WEB = False` to `dtable_web_settings.py`.
## Basic settings
```python
# The URL of dtable-web that for users to visit your SeaTable server
DTABLE_WEB_SERVICE_URL = 'https://seatable.yourdomain.com/'
# The file server URL
FILE_SERVER_ROOT = 'https://seatable.yourdomain.com/seafhttp/'
# Redirect URL when logout,if not set, it will redirect to the SeaTable default page of logout
LOGOUT_REDIRECT_URL = 'https://example.com/'
```
If you changed your domain, the URLs in above settings must be changed accordingly.
## Sending Email Notifications
Refer to [email sending documentation](../sending-email.md).
## User management options
The following options affect user registration, password and session.
```python
# Enable or disable registration on web. Default is `False`.
ENABLE_SIGNUP = False
# Activate or deactivate user when registration complete. Default is `True`.
# If set to `False`, new users need to be activated by admin in admin panel.
ACTIVATE_AFTER_REGISTRATION = True
# Whether or not send activation Email to user when registration complete. Default is `False`.
# This option will be ignored if `ACTIVATE_AFTER_REGISTRATION` set to `True`.
REGISTRATION_SEND_MAIL = False
# Whether allow user to delete its account. Default is `True`.
ENABLE_DELETE_ACCOUNT = True
# Enforce all users to use 2-factor-authentication. Default is 'False'.
# Changing 'True' to 'False' will deactivate 2FA for all users (they could still activate it
# in their personal settings).
ENABLE_FORCE_2FA_TO_ALL_USERS = True
# Whether to send email when a system admin adding a new member. Default is `True`.
SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER = True
# Whether to send email when a system admin resetting a user's password. Default is `True`.
SEND_EMAIL_ON_RESETTING_USER_PASSWD = True
# Whether to send email when an admin activates a new account. Default is `True`.
SEND_EMAIL_ON_ACTIVATING_USER = True
# Whether to send email when add new user. Default is `True`.
SEND_EMAIL_ON_ORG_ADD_NEW_USER = True
# Whether to send email when org admin activating a member. Default is `False`.
SEND_EMAIL_ON_ACTIVATING_ORG_USER = False
# Send system admin notify email when user registration is complete. Default is `False`.
NOTIFY_ADMIN_AFTER_REGISTRATION = True
# Remember days for login. Default is 7
LOGIN_REMEMBER_DAYS = 7
# Attempt limit before showing a captcha when login.
LOGIN_ATTEMPT_LIMIT = 3
# deactivate user account when login attempts exceed limit
FREEZE_USER_ON_LOGIN_FAILED = False
# minimum length for user's password
USER_PASSWORD_MIN_LENGTH = 6
# LEVEL based on four types of input:
# num, upper letter, lower letter, other symbols
# '3' means password must have at least 3 types of the above.
USER_PASSWORD_STRENGTH_LEVEL = 3
# default False, only check USER_PASSWORD_MIN_LENGTH
# when True, check password strength level, STRONG(or above) is allowed
USER_STRONG_PASSWORD_REQUIRED = False
# Force user to change password when admin add/reset a user.
FORCE_PASSWORD_CHANGE = True
# Whether to allow SSO users to set a local password; default True, admin or user can set a local password by 'Reset password'
ENABLE_SSO_USER_CHANGE_PASSWORD = True
# Whether to allow LDAP users to set a local password; default False, when True, admin or user can set a local password by 'Reset password'
ENABLE_LDAP_USER_CHANGE_PASSWORD = False
# Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
# Whether a user's session cookie expires when the Web browser is closed.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
# Whether to save the session data on every request. Default is `False`
SESSION_SAVE_EVERY_REQUEST = False
# Whether to allow a user to create a base in personal workspace. Default is `False`
DISABLE_ADDING_PERSONAL_BASES = False
# Whether to show the option to generate an account token in the personal settings Default is `True`
ENABLE_GENERATE_WEB_API_TOKEN_IN_WEB = True
```
## Other options
```python
# Choices can be found here:
# https://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# Otherwise there may be problems with the export or data processing
# of the date-column.
# Here some examples:
TIME_ZONE = 'UTC'
TIME_ZONE = 'Europe/Berlin'
TIME_ZONE = 'America/New_York'
# Disable settings via Web interface in system admin->settings
# Default is True
ENABLE_SETTINGS_VIA_WEB = False
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
# Default language for sending emails.
LANGUAGE_CODE = 'en'
# Custom language code choice.
LANGUAGES = (
('en', 'English'),
('zh-cn', '简体中文'),
('zh-tw', '繁體中文'),
)
# Set this to your website/company's name. This is contained in email notifications and welcome message when user login for the first time.
SITE_NAME = 'SeaTable'
# Browser tab's title
SITE_TITLE = 'Private SeaTable'
# Configure user help pages
HELP_LINK = 'https://seatable.com/help/'
# Add privacy policy link and terms link
PRIVACY_POLICY_LINK = ''
TERMS_OF_SERVICE_LINK = ''
# Predefined custom colors that can be used in color rules, options of single select and so on
CUSTOM_COLORS = [
{'color':'#F5C043','text_color':'#212529'},
{'color':'#3064BC','text_color':'#FFFFFF'},
]
# Default Seafile Server URL used in third party integration
DEFAULT_SEAFILE_SERVER = 'https://seafile.example.com/'
```
## Group member limit
SeaTable groups are subject to a member limit.
```python
GROUP_MEMBER_LIMIT = 500 # users, 500 is the default value
```
## Big data import / export limits
When importing / updating a base from excel or exporting an big data view to Excel, you can set the maximum number of rows in the configuration file:
```python
ARCHIVE_VIEW_EXPORT_ROW_LIMIT = 250000
BIG_DATA_ROW_IMPORT_LIMIT = 500000
BIG_DATA_ROW_UPDATE_LIMIT = 500000
```
In addition, there's a file size limit of 40MB per XLSX file. This limit cannot be configured.
## Base export limit
SeaTable exports bases in DTABLE files. A DTABLE file contains all tabular data, assets, and a lot of metadata and can thus become large.
This is the max size allowed for an export via the Webinterface of SeaTable. For the export via command line, there is another parameter `max_download_dir_size` in seafile.conf.
```python
DTABLE_EXPORT_MAX_SIZE = 100 # in MB, 100MB is the default value
```
## Common dataset limits
SeaTable synchronizes common datasets manually and automatically. The sync frequency is limited. The parameter `SYNC_COMMON_DATASET_INTERVAL` defines the minimum time between two syncs.
```python
SYNC_COMMON_DATASET_INTERVAL = 5 * 60 # in seconds, 300 is the default value
```
## Limit of collaborators loaded in a base
After opening a base, the first 300 collaborators and the first 100 external application accounts are loaded by default. These data are used to select collaborators in the collaborator column. If you need to load more collaborators, you can modify the following parameters.
```python
DTABLE_RELATED_USERS_PER_PAGE = 300
DTABLE_APP_USERS_PER_PAGE = 100
```
## Embed bases into other webpages
To embed bases into other webpages using an iframe, the following options must be added to support user login:
```python
SESSION_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True
```
## RESTful API
API throttling related settings. Enlarge the rates if you got 429 response code during API calls.
API_THROTTLE_RATES is used to replace the old REST_FRAMEWORK option. API_THROTTLE_RATES is empty by default. You can add your custom THROTTLE_RATE to the option
```python
API_THROTTLE_RATES = {
'ping': '3000/minute',
'anon': '60/minute',
'user': '3000/minute',
'sync_common_dataset': '60/minute',
'password_reset': '10/minute',
'org-admin': '1000/day',
'app': '1000/minute',
'import': '20/minute', # Limit the rate of API calls for importing via excel/csv
'export': '20/minute', # Limit the rate of export base, table and view
}
# Throttling whitelist used to disable throttle for certain IPs.
# e.g. REST_FRAMEWORK_THROTTING_WHITELIST = ['127.0.0.1', '192.168.1.1']
# Note: The name of this setting contains an unintended typo (`THROTTING` instead of `THROTTLING`)
REST_FRAMEWORK_THROTTING_WHITELIST = []
```
## Trash retention period
SeaTable keeps a deleted base in trash for a certain period of time (retention period). When the retention period expires, the base is purged from trash.
```python
TRASH_CLEAN_AFTER_DAYS = 30 # in days, 30 days is the default value
```
---
Source: https://admin.seatable.com/configuration/components/seafile/
# Configuration of Seafile
This is a cheat sheet for the [seaf-server](/introduction/architecture.md#seaf-server) configuration file `seafile.conf`. It contains all possible settings that can be configured as well as their default values.
The default values provided here are best-effort (not built automatically). They will be used, if no value is defined at all. It is not necessary the value, that is written in the configuration file on first startup.
In the default values below, a value in the form `$XYZ` refers to an environment variable.
??? tip "Configuration changes require a restart"
New configuration options will only apply after a restart of SeaTable.
??? abstract "Notes about the configuration file format"
The configuration file uses the **INI format**, which is a simple text-based format for storing configuration data. It consists of sections (denoted by square brackets, e.g., [general]) and key-value pairs.
Comments in the configuration file start with the hash symbol `#` and extend to the end of the line.
When dealing with special characters like single quotes `'`, double quotes `"` or the hash symbol `#`, it's generally best to enclose the value in double quotes.
The following options are grouped by their sections.
## Example configuration
This is a typical configuration file, created automatically on the first startup by SeaTable.
```ini
[fileserver]
port=8082
[history]
keep_days = 60
```
## Available configuration options
### `[fileserver]`
| Parameter | Description | Default |
| ---------------- | -------------------------------------------------------------------------------------------------- | ------- |
| `host` | The address the fileserver listens on. You can set this to `127.0.0.1` to further restrict access. | 0.0.0.0 |
| `port` | The port the fileserver listens on. | 8082 |
| `worker_threads` | The number of worker threads used to serve HTTP requests. | 10 |
| `max_download_dir_size` | Maximum size of the assets in a base that could be exported via command line in MB. | 100 |
### `[history]`
| Parameter | Description | Default |
| ----------- | ---------------------------------------------- | ------- |
| `keep_days` | How many days the file history should be kept. | 60 |
### `[database]`
Since version 5.3, Seafile reads the main database configuration settings from [environment variables](/configuration/overview).
The following options are optional and can be used to further tweak Seafile:
| Parameter | Description | Default |
| -------------------- | ----------------------------------------------------- | ------- |
| `connection_charset` | The connection charset to use. | |
| `max_connections` | Size of the connection pool for database connections. | 100 |
## Deprecated or removed options
### `[database]`
??? note "[database] is not necessary anymore"
Since version 5.3, `Seafile` reads the main database settings from [environment variables](/configuration/overview).
The section `[database]` contained options for accessing the MariaDB database used by `Seafile`.
- `type`: Database connection type. Use `mysql` for MySQL and MariaDB. Other databases are not yet supported.
- `host`: Address of database. You must provide this option.
- `port`: Port of database. Defaults to 3306.
- `username`: Username for login to the database. You must provide this option.
- `password`: Password for the database user. You must provide this option.
- `db_name`: Database name used by `seafile_db`. You must provide this option.
---
Source: https://admin.seatable.com/configuration/components/gunicorn/
# Configuration of Gunicorn
Gunicorn is used within the SeaTable Docker container as the WSGI server that runs the main web application and API processes (account endpoints). It sits between the web server **nginx** and the SeaTable Python code, efficiently handling concurrent user requests and ensuring robust performance.
SeaTable automatically configures Gunicorn with optimal settings for most deployments. Adjustments are only required in advanced scenarios, such as customizing performance, logging, or security settings. For most administrators, the default configuration ensures secure and efficient operation.
## Example configuration
A typical Gunicorn configuration file is created automatically by SeaTable during the first startup:
```python
daemon = True
workers = 5
threads = 5
# default localhost:8000
bind = '127.0.0.1:8000'
# Pid
pidfile = '/var/run/dtable-web.pid'
# for file upload, we need a longer timeout value (default is only 30s, too short)
timeout = 1200
limit_request_line = 8190
# Log
#accesslog = '/opt/seatable/logs/gunicorn-access.log'
#errorlog = '/opt/seatable/logs/gunicorn-error.log'
```
---
Source: https://admin.seatable.com/configuration/components/nginx/
# Configuration of Nginx
SeaTable automatically generates a default `nginx.conf` file in the configuration folder. **Since version 5.3, we no longer use this file.**
The reason for this change is that SeaTable updates often require modifications to the `nginx.conf` file to support new features. These changes are not customer-specific and can complicate the update process. To simplify updates and ensure stable, maintainable configurations, we now provide a custom `nginx.conf` file together with the YAML configuration files. This custom file, located in the compose folder (`/opt/seatable-compose`), is mounted into the container at startup.
**As a result, the `nginx.conf` file in the container’s configuration folder is obsolete.**
## Customizing Nginx Configuration
When you update SeaTable, all default files in `/opt/seatable-compose` will be overwritten.
This includes all changes that you may do in `nginx.conf` and `seatable-server.yml`.
You should read our guide that explains how to [customize the configuration](../customizations.md) of your instance before proceeding.
To preserve your custom configuration settings, follow these steps:
1. **Create a Copy:**
Make a copy of the `seatable-nginx.conf` file (e.g. `custom-seatable-nginx.conf`) in your compose folder (`/opt/seatable-compose`).
2. **Edit the Custom File:**
Make any necessary changes to your custom NGINX configuration file.
**Note:** All future modifications should be made to this custom file to ensure that your modifications are preserved across version upgrades.
3. **Mount the Custom Config File:**
Create a `custom-seatable-server.yml` file that contains a volume mount for your custom NGINX file:
```yaml
services:
seatable-server:
volumes:
- ./custom-seatable-nginx.conf:/etc/nginx/sites-enabled/default
```
4. **Update the .env File:**
In your `.env` file, update the `COMPOSE_FILE` variable to include your `custom-seatable-server.yml` file (if this is not already the case).
5. **Apply the Changes:**
Run `docker compose up -d` inside the directory `/opt/seatable-compose` in a terminal for your changes to take effect.
This ensures that your custom configuration is used instead of the original file.
---
## UI Customization
Source: https://admin.seatable.com/customization/overview/
# UI Customization in SeaTable
SeaTable Server offers numerous options for tailoring the system to your specific needs. This includes customization of colors, logos, images, emails and HTML templates. While most customization tasks can be performed via the command line interface, system administrators also have the ability to make certain changes directly through the web interface.
Let's explore the various possibilities for UI customization

## Where to find the configuration files?
You don't have to switch to the SeaTable docker container, to make changes at the configuration files. The configuration files of a SeaTable server can usually be found in the host server at the directory `/opt/seatable-server/seatable/conf/`.
Use the editor of your choice like `nano` or `vim` to edit the files.
## How to persist changes
Please be aware that any change that you do inside a docker container will be removed if the changed files are not mounted to the host system.
Also changes should never be done in the directory `seatable-server-latest`. This folder will always be replaced as soon as you upgrade to another version.
Keep this in mind, but the articles will explain precisely where you should do the changes.
## How to restart SeaTable?
Changes in the configuration files, require a restart of the SeaTable container or the SeaTable service.
Read [here, how to restart SeaTable or the complete container](../maintenance/restart-seatable.md).
---
Source: https://admin.seatable.com/customization/site-title/
# Site Title and Site Name
**Site Title** and **Site Name** are two basic customization options. The **Title** is used in the browser tab and the **Name** is used in notifications or email messages.

Please be aware that if you define a value in the webinterface, this always overrules the value in the config file.
## Configuration via the web interface
Login to your SeaTable Server as system administrator and switch to the system admin area. Select the navigation point `Settings`. Team admins or normal users do not have the permission to access the system admin area.

Add a new **Title** and/or **Name** and save the values. The changes are live right away.
## Configuration via config file
Add these configurations to `dtable_web_settings.py` and restart SeaTable service.
```bash
# Browser tab's title
SITE_TITLE = 'Private SeaTable'
# Set this to your website/company's name.
# The title is used in email notifications and welcome messages.
SITE_NAME = 'SeaTable'
```
---
Source: https://admin.seatable.com/customization/logo/
# Logo
The Logo of your SeaTable server can easily be replaced via the web interface or the command line.
## Configuration via the web interface
Login to your SeaTable Server as system administrator and switch to the system admin area. Select the navigation point `Settings`.

Click on `Change` and select a new image file with the recommended resolution of 256\*64 px. After a page reload the new logo is visible.
It is recommended that your logo has a transparent background because it is used on the login-page, emails and also the web interface.
SeaTable will save the logo as `mylogo.png` on the server at `/opt/seatable-server/seatable/seahub-data/custom/`.
## Configuration via the command line
Instead of upload the logo via the webinterface, you could also create the logo file via the command line. SeaTable expects that you generate a file called `mylogo.png` in the directory `/opt/seatable-server/seatable/seahub-data/custom/`.
The directory `custom` does not exist in general, therefore you might have to create it first.
```bash
mkdir /opt/seatable-server/seatable/seahub-data/custom/
cp mylogo.png /opt/seatable-server/seatable/seahub-data/custom/mylogo.png
```
If your logo is not immediately visible after a page reload, you have to restart the SeaTable container (not the SeaTable service).
The SeaTable container has to create a symlink to make the logo file available to SeaTable.
---
Source: https://admin.seatable.com/customization/favicon/
# Replace Favicon in SeaTable
SeaTable allows you to easily replace the default SeaTable favicon with a custom one. SeaTable uses two favicons: a default one { width="24"} and a notification favicon { width="24" } that appears when you have unread notifications.
## Configuration via the Web Interface
Currently, it is not possible to replace these favicons through the system administrator interface.
## Configuration via the Command Line
Instead of uploading favicons via the web interface, you must save them on the host using the command line. Simply save your favicons to the following paths and restart your container:
- `/opt/seatable-server/seatable/seahub-data/custom/seatable-favicon.ico`
- `/opt/seatable-server/seatable/seahub-data/custom/seatable-notification.ico`
If the `custom` directory does not exist, you will need to create it.
### Custom Path
If you prefer to use a different file name, you can modify this by adding the following settings to `dtable_web_settings.py`. The path must be publicly available and is therefore relative to the media path. SeaTable supports both `png` and `ico` files.
```python
CUSTOM_FAVICON_PATH = 'custom/my-favicon.png'
CUSTOM_FAVICON_NOTIFICATION_PATH = 'custom/my-notification-favicon.png'
```
---
Source: https://admin.seatable.com/customization/manual-in-nav/
# Custom manual
By default SeaTable presents a "Manual" link on its home page. Starting with version v4.4 this link points to but in all former versions, the link opened only a blank new browser tab.

Luckily it is super easy to change the behaviour of this manual link and to change the target URL.
## Setup the target URL of the manual link
Open the configuration file `dtable_web_settings.py` located at `/opt/seatable-server/seatable/conf/` and add this configuration line. Change the value to your needs.
```bash
HELP_LINK = 'https://seatable.com/help/'
```
Don't forget to [restart SeaTable service](../maintenance/restart-seatable.md).
---
Source: https://admin.seatable.com/customization/nav-items/
# Additional Navigation Items
SeaTable provides an easy way to add custom navigation items below the _Help and Resources_ section on the left side of the page. For example, you can add a link to a status page (like from Gatus or Uptime Kuma).
Here's how it might look:

## Configuration
To add new items, simply append the following code to your `dtable_web_settings.py`. You can choose from nearly 400 available icons for the `icon` field. Use the search function below to find the perfect one.
```python
CUSTOM_NAV_ITEMS = [
{
'icon': 'dtable-icon-app-statistics',
'desc': 'Status Page',
'link': 'https://stats.uptimerobot.com/R5GVEtrQK8'
}
]
```
## Search for Icons in SeaTable
Browse through nearly 400 available icons in SeaTable by typing a keyword and pressing **Enter**. This will display all matching results. For a comprehensive view, type `dtable-icon` to see the entire collection of available icons.
---
Source: https://admin.seatable.com/customization/main-color/
# Change the main color
SeaTable has an orange main color with the color-code `#FF8000`. If this color does not match your custom logo, it might be useful to replace this main color with another color of your choice.
To do this we force SeaTable to use custom css code to overwrite the main color.
The first step is you use the following color picker and select a new main color of your choice.
You should select a color that is dark enough to be a good background for white font color. To switch also the font color from white to black is not yet part of this manual.
Please be aware that if you define a value in the webinterface, this always overrules the value in the config file.
=== "Version 6.2"
Select a color and you will get the correspondent css code in the following grey box.
```css
Select a color and the css code will be created...
```
Use the copy-and-paste icon (:material-content-copy:) on the top right of the grey box to copy the complete css code to your clipboard.
=== "Version 6.1"
Select a color and you will get the correspondent css code in the following grey box.
```css
Select a color and the css code will be created...
```
Use the copy-and-paste icon (:material-content-copy:) on the top right of the grey box to copy the complete css code to your clipboard.
=== "Version 6.0"
Select a color and you will get the correspondent css code in the following grey box.
```css
Select a color and the css code will be created...
```
Use the copy-and-paste icon (:material-content-copy:) on the top right of the grey box to copy the complete css code to your clipboard.
=== "Version 5.3"
Select a color and you will get the correspondent css code in the following grey box.
```css
Select a color and the css code will be created...
```
Use the copy-and-paste icon (:material-content-copy:) on the top right of the grey box to copy the complete css code to your clipboard.
=== "Version 5.2"
Select a color and you will get the correspondent css code in the following grey box.
```
Select a color and the css code will be created...
```
Use the copy-and-paste icon (:material-content-copy:) on the top right of the grey box to copy the complete css code to your clipboard.
## Configuration via the web interface
Login to your SeaTable Server as system administrator and switch to the system admin area. Select the navigation point `Settings`. Team admins or normal users do not have the permission to access the system admin area.
First you should set the checkbox for `ENABLE_BRANDING_CSS`. Then simply copy and paste (:material-content-copy:) the css code and paste it to the input box of `Custom CSS`. Submit by clicking on the green :material-check:.
Reload your page of your browser and the color should be changed.
## Configuration via config file
Open the configuration file `dtable_web_settings.py` and add this configuration line:
```bash
BRANDING_CSS = 'custom/custom.css'
```
Now copy the css code from this manual and save it to `/opt/seatable-server/seatable/seahub-data/custom/custom.css`. If the directory `custom` does not exist, you have to create it first.
If your new color is not immediately visible after a page reload, you have to restart the SeaTable container (not the SeaTable service).
The SeaTable container has to create a symlink to make the css file available to SeaTable.
---
Source: https://admin.seatable.com/customization/custom-css/
# Custom CSS
SeaTable provides the flexibility to incorporate custom CSS code, allowing users to either conceal specific elements or modify their behavior. This article showcases several examples of what you can achieve with CSS customization.
## How to add custom CSS
Custom css can be added as system admin via the browser of via the command line.
Please refer to the article [main color](../customization/main-color.md) to get an explanation how to add custom css code.

## Examples of custom CSS
### Example: Switching Column Selection to a Single Row
If you've transitioned from using to a self-hosted system, you may have noticed a difference in how new columns are added. SeaTable Cloud presents the available column types in a single-row list, while your self-hosted server displays them in a two-row box.
**Two-Row Selection in a Self-Hosted Server**

**Single-Row Selection, as in SeaTable Cloud**

To achieve a single-row display like in SeaTable Cloud, add the following CSS styles:
```bash
.select-column-popover .select-column-list .select-column-title {display:none;}
.select-column-popover .select-column-list {display:block !important;}
.select-column-popover .select-column-list .select-column-item {width:100% !important;}
.mobile-editor-column .select-column-container .am-list-header {display:none;}
```
---
Source: https://admin.seatable.com/customization/templates/
# Templates
Templates offer a convenient method for offering predefined base structures to your users. Adding and managing templates in SeaTable is straightforward since each template is just a SeaTable base and essentially all templates are managed in a **main template** base.
Simply by adding a row to the designated **main template** base, it instantly becomes available in the list of templates.

Sounds easy? Actually it is easy.
## Establishing Your Template Base
To begin, you'll need to create a base that will serve as the repository for all the templates you intend to offer your users. Let's call this the **main template** base.
### Recommended Structure
Here's a suggested approach for organizing your templates:
1. **Create a New Group**: Start by creating a group titled `Templates`.
1. **Main Template Base**: Within this group, set up a base named `All templates`.
1. **Organize Categories**: Utilize folders within the group to categorize your templates based on different themes or purposes.
1. **Template Creation**: Create individual bases within each category folder to accommodate your various templates.
1. Create a new group with the name `Templates`
1. in this group, there will be a base with the name `All templates`.
1. Add folders in your group for each category you would like to provide.
1. Create as many bases in the category folder as you want.
Here's an example of how the structure might appear. In this illustration, I've included folders for both _Marketing_ and _Projects_ categories.

### Creating the Main Template Base
You have two options for setting up the master template base:
??? "Option 1: Download and Import"
The simplest method is to download our predefined dtable file and import it into your SeaTable server to create the **main template** base.
[Download our predefined template base](../downloads/All templates.dtable){ .md-button .md-button--primary }
??? "Option 2: Create it from Scratch"
Alternatively, you can create the base from scratch. Your base should include the following columns:
- **name** [text]: An internal name for distinguishing between different templates.
- **category** [single-select]: Categorization of the template.
- **display_name** [text]: The name of the template displayed on the website.
- **description** [long-text]: Introduction and suggestions for the template.
- **card_image** [image]: Image displayed on the template panel.
- **card_image_expanded** [image]: Image displayed in the template detail dialog.
- **link** [url]: The sharing link for the specific template.
Ensure that the table name is `templates`. You can name the base whatever you prefer.
Below is an example of how the **main template** base could be structured:

### Recommended size of template images
To ensure optimal display in the SeaTable **main template**, please provide two different images with the following dimensions:
- **card_image**: 560 x 240 pixels
- **card_image_expanded**: 1840 x 400 pixels
## Create your Templates
Now it's time to create your initial bases, which you'll offer as templates. As recommended, organize these templates within folders.
Once you've created your bases, you'll need to generate **external links** for each base and paste them into your master template base. Refer to this help article from the user documentation on [how to create external links](https://seatable.com/help/external-link-explained-seatable).
You can add more templates to your **main template** base at any time. They'll be immediately accessible to all users, and no restart is required.
## Generate an API Token for Your Base
Now that you've set up your master base and created some template bases, it's time to generate an API token for the master base. Refer to this help article from the user documentation on [how to create an API token](https://seatable.com/help/create-api-tokens).
Make sure to note down the API token as you'll need it for the next step.
## Activate templates in SeaTable
Equipped with API token and your template base, you can activate the templates in your SeaTable Server.
The SeaTable Server image supports auto configuration via environment variables. Add these variables to your .env file.
| Environment variable | Description | Example values |
| ------------------------------------------- | ----------------------------------------------- | ----------------------- |
| `SEATABLE_SHOW_TEMPLATES_LINK` | Activate to show the link on the home page | `true` or leave empty |
| `SEATABLE_TEMPLATE_BASE_API_TOKEN` | API token of the base containing your templates | `759...3a05f8` |
| `SEATABLE_TEMPLATE_TABLE_NAME` | Name of the table containing your templates | `Table1` or `Templates` |
| `SEATABLE_ENABLE_CREATE_BASE_FROM_TEMPLATE` | Allow the creation of new bases from templates | `true` or leave empty. |
Restart SeaTable service to activate your templates.
:partying_face: **Congratulations!** Every user can now use these templates.
---
Source: https://admin.seatable.com/customization/page-templates/
# SeaTable Frontend Modification
With the help of [dtable_web_settings.py](../configuration/components/dtable-web.md) SeaTable offers a wealth of configuration options to enable or disable individual functions in the frontend or to customize the frontend to your own needs.
At the same time, you can only intervene in the design of the frontend to a limited extent with the help of the configuration files. For this, SeaTable offers a sophisticated template system to selectively replace individual page areas with their own versions.
This article introduces this form of customizing.
## What can be customized?
SeaTable uses predefined HTML templates for almost all web pages and emails, which can be customized. Changes to the base editor are thus not possible, but adjustments to the login page or changes to individual email texts are possible without problems.
The basic idea is simple. You take the files provided by seatable and copy them to a special place outside the container. These copied files can then be customized. If SeaTable (after a restart) finds these files, they will be used instead of the original files. The duplicated and customized files are stored outside the SeaTable docker container, so that the customizations survive an update of SeaTable.
All files below `/opt/seatable/seatable-server-latest/dtable-web/seahub/templates/` (inside the SeaTable container) can be customized. Here are a few examples that lend themselves to this:
- **404.html**: Error page, if the URL is not available.
- **500.html**: Error page, in case of a critical error
- **registration/login.html**: Login page
- **registration/logout.html**: Logout page
- **registration/registration_form.html**: Self-registration page
- **registration/activation_email.html**: E-Mail after self-registration (if activation is required)
- **shared_link_email.html**: E-Mail if somebody shares a link with another user
There are many more files, and all of them can be customized.
## How to customize these files?
The basic approach is simple. Create a custom folder in your host system (usually `/opt/seatable-server/seatable/seahub-data/custom`) and copy the files you want to change to this folder. After a restart SeaTable will check for existing files in your custom directory and replace the original files with the new ones.
**IMPORTANT NOTES:**
1. Files must not be renamed. If the file is called `404.html`, then the file has to keep this name. Otherwise the replacement with your custom files will not work.
2. Keep the files in the same directory structure. If you want to replace `registration/login.html`, then you have to create a folder `registration` in your custom folder and copy the file `login.html` to this new directory.
Imagine this customizing like an overlay. SeaTable takes the original files from inside the container. If SeaTable finds the files with the same name in the same directory structure, it replaces the original files.
## Example: new login page
Imagine you want to replace the login page of SeaTable with something fancier. Here is what you have to do. The following example assumes that your SeaTable docker container is called `seatable-server` and that your mounted docker volume is located at `/opt/seatable-server`. Please check your docker-compose.yml and change the following examples if necessary.

### 1. Create custom folder
This step must be done only once. It generates the setup that you can start overwrite existing html-files from SeaTable with your own ones. You need the folder to save the copies outside of your docker container and you need a symlink that SeaTable can find your custom files.
```bash
cd /opt/seatable-server/seatable/seahub-data
mkdir -p custom/templates/registration
docker exec -it seatable-server ln -s /shared/seatable/seahub-data/custom /opt/seatable/seatable-server-latest/dtable-web/media/custom
```
### 2. Copy the original login.html to your custom folder
```bash
$ docker cp seatable-server:/opt/seatable/seatable-server-latest/dtable-web/seahub/templates/registration/login.html /opt/seatable/seatable-data/seatable/seahub-data/custom/templates/registration/login.html
```
### 3. Adapt the login.html according to your needs
Now you can start editing your login.html. Otherwise you can take one of these examples (tested with SeaTable 4.0.x):
**Example 1: Simple login form**

Copy the following content to your login.html. As you can see, the login page was reduced to the maximum. There is no box around the input fields, there is no _language selector_, no _single sign on_, no _signup_ or _forget password_. Error messages are still shown and security features like _CSRF_ and _Captcha_ is still part of the login page.
```html
{% extends "base_clean.html" %}
{% load i18n %}
{% block private_style %}
.show-password-toggle {
position: absolute;
top: 8px;
right: 10px;
cursor: pointer;
color: #999;
}
.show-password-toggle:hover {
color: #666;
}
.login-panel {
background: none;
border-radius: none;
box-shadow: none;
}
.vh {
visibility: inherit !important;
}
{% endblock %}
{% block main_content %}
{% endblock %}
{% block extra_script %}
{% endblock %}
```
### 4. Restart seatable service
Now [restart SeaTable](../maintenance/restart-seatable.md) to activate your new login page.
## Customize CSS
Create customize folder, add your css file to custom/, for example, `custom.css`
```sh
mkdir -p /opt/seatable-server/seatable/seahub-data/custom
cd /opt/seatable-server/seatable/seahub-data/custom
vim custom.css
docker exec -it seatable-server ln -s /shared/seatable/seahub-data/custom /opt/seatable/seatable-server-latest/dtable-web/media/custom
```
Then modify `BRANDING_CSS` in `dtable_web_settings.py`
```py
BRANDING_CSS = 'custom/custom.css'
```
Restart SeaTable container
```sh
docker compose restart
```
## Translation
In the HTML files you will see strings like `{% trans "Forgot password?" %}`. This is a placeholder, that will be replaced by other language strings depending on which language the user has selected. Translations and changes to these language strings is not part of this article. There will be another article in the near future.
---
Source: https://admin.seatable.com/customization/template-snippets/
# Template Snippets
Since version v6.2, [`dtable-web`](../introduction/architecture.md#dtable-web) allows injecting a custom [Django template](https://docs.djangoproject.com/en/4.2/topics/templates/) snippet into certain HTML templates.
This template snippet is included into the following HTML templates:
| Template | Purpose |
| ----------------------------- | ------------------------------------------- |
| `react_dtable.html` | Used when rendering the SeaTable dashboard. |
| `dtable_file_view_react.html` | Used when a base is opened. |
| `base_for_external_app.html` | Used when a universal app is opened. |
## Mounting the HTML file
In order to inject a snippet, an additional volume mount must be added to the `seatable-server` service.
You should use an [additional `.yml` file](../configuration/customizations.md) to accomplish this.
```yaml
services:
seatable-server:
volumes:
- ./custom_body_snippet.html:/shared/seatable/seahub-data/custom/templates/custom_body_snippet.html
```
The filename on the host may differ, but you must mount the file to this exact location.
You can use Django's full templating capabilities inside the HTML file.
Do not forget to restart the container once you're done:
```bash
cd /opt/seatable-compose
docker compose up -d
```
## Use Cases
Here are some use cases for this feature:
- Web analytics
- Error tracking
- Customizing the UI via JavaScript
---
## Upgrade
Source: https://admin.seatable.com/upgrade/upgrade-manual/
# Upgrade manual
Updating/Upgrade (we don't differentiate) a SeaTable Server should take just a few seconds. Simply pull the latest Docker images for all components, restart the containers, and let the system automatically handle necessary database updates. Within moments, all essential services of the SeaTable Server will be accessible.
After upgrading SeaTable, rolling back to a previous version is not supported due to possible changes in the database and files. Attempting to downgrade can cause data loss or system errors.
**Always make a full backup before upgrading.** For instructions, see [Backup and Recovery](../maintenance/backup-recovery.md) for more details.
## How to update SeaTable Server
Updating SeaTable and all additional components involves the following steps:
1. Updating the `.yml` files
2. Following the extra upgrade notices for the target version
3. Applying changes
4. Updating the installed plugins
These steps are explained in the following sections.
### Updating the `.yml` files
The following command replaces all predefined `.yml` files in your `/opt/seatable-compose` folder.
It will not touch your .env file and any "custom" `.yml` files that contain overrides.
Please read our guide that describes how the [configuration can be customized](../configuration/customizations.md).
This ensures that version upgrades stay seamless.
If you've previously made changes to the predefined `.yml` files, make sure to save these changes and follow the [recommendations above](../configuration/customizations.md) instead.
You can update all `.yml` files inside `/opt/seatable-compose` by running the following command:
```bash
cd /opt/seatable-compose && \
wget -c https://github.com/seatable/seatable-release/releases/latest/download/seatable-compose.tar.gz \
-O - | tar -xz -C /opt/seatable-compose
```
Note that running this command does not **yet** affect running containers.
### Extra upgrade notices
Please review and follow the [extra upgrade notices](./extra-upgrade-notice.md) for the version you're upgrading to before proceeding.
This ensures that SeaTable will start correctly after upgrading.
Upgrading to version v6.2 requires various configuration changes. Please carefully read the [extra upgrade notices](./extra-upgrade-notice.md)
### Applying changes
After addressing the version-specific changes in the [extra upgrade notices](./extra-upgrade-notice.md), you're ready to apply the changes to the `*.yml` files.
This can be achieved by running the following commands:
```bash
cd /opt/seatable-compose
docker compose pull
docker compose down
docker compose up -d
```
After some seconds your SeaTable Server should be reachable again. You can check the current version of your SeaTable Server opening the URL `https:///server-info`.
Please refer to the [troubleshooting section](../installation/faq.md) of the admin manual in case you're running into issues.
### Updating plugins
After updating SeaTable Server, you should update all installed plugins inside the system admin area.
This ensures that you're running plugin versions that are compatible with your SeaTable Server version.
You can find more information about the plugin update process [here](../configuration/plugins.md).
---
## Naming conventions and update path
SeaTable follows typical naming conventions for updates:
- **2** :material-chevron-double-right: **3** is a major version upgrade.
- **3.3** :material-chevron-double-right: **3.4** is a minor version upgrade.
- **3.3.3** :material-chevron-double-right: **3.3.5** is a patch upgrade.
Some software solutions require that you follow a specific update path. Meaning like you first have to upgrade to the next major version and then go on. **This is not necessary with SeaTable.**
You can update from any version to the last one in one step. SeaTable v4.3 and newer take care of the required database updates.
## Update procedure with one single docker-compose.yml (deprecated)
With version 4.3 we introduced a new way to install, update and maintain a SeaTable server. Before 4.3 you used to have one big docker-compose.yml. Even if it is not mandatory to switch to this setup, we recommend it. Please check out this [article for more details](./migrate-seatable-release.md).
Open your `docker-compose.yml` file and search for `seatable/seatable-enterprise:{tag}`. Replace the {tag} with the latest version and save the file.
Now, execute these commands to pull and start the newest version.
```bash
docker compose pull
docker compose up -d
```
This will not update any other service in your docker-compose file. You have to take care by yourself to keep the other services up-to-date. Therefore it is recommended to migrate to the newest installation method with multiple YAML files.
## Update procedure before v4.3 (deprecated)
This part of the manual is only for older version, meaning if you are updating to version v4.2 or older. As soon as you update to version 4.3 or newer, you can ignore the following part.
??? note "Update procedure before v4.3"
In general, to upgrade to a new version, you need to
1. Pull a new docker image version
2. Stop the service and do the database migration manually
3. Restart the service
If there are extra notes for a specific version, you can find it here: [extra notices](./extra-upgrade-notice.md)
### Get latest SeaTable
You can find all versions of SeaTable from [Docker Hub](https://hub.docker.com/r/seatable/seatable-enterprise/tags).
Run the following command to get the latest version of Seatable.
```bash
docker pull seatable/seatable-enterprise:{tag}
```
Stop the currently running SeaTable container.
```bash
docker compose down
```
Then modify SeaTable version in "docker-compose.yml". And start a new SeaTable container.
```bash
docker compose up -d
```
### Upgrade database
Major version upgrade, like from 1.x to 2.x, and minor version upgrade, like from 1.1.x to 1.2.x, involve database changes. You need to manually change the database like following.
Login to the SeaTable container. Then execute the upgrade statement (replace the version numbers accordingly).
```bash
# Example of the required commands to update from 3.2.6 to 3.5.10
docker exec -it seatable /bin/bash
seatable.sh upgrade-sql 3.3
seatable.sh upgrade-sql 3.4
seatable.sh upgrade-sql 3.5
```
If the above commands failed to execute for some reasons, (for example, you are using external database instead of the default one started by docker-compose), you can execute the database upgrade commands manually as below:
```bash
docker exec -it seatable /bin/bash
cd /opt/seatable/seatable-server-latest/sql/mysql/upgrade
mysql -h$DB_HOST -p$DB_ROOT_PASSWD dtable_db < ./3.3/dtable.sql
mysql -h$DB_HOST -p$DB_ROOT_PASSWD dtable_db < ./3.4/dtable.sql
mysql -h$DB_HOST -p$DB_ROOT_PASSWD dtable_db < ./3.5/dtable.sql
```
If you upgrade several versions at once, just run all the database upgrade statement one by one, starting from the lowest version.
!!! hint "Tiny version update"
Tiny version upgrade, like from 3.3.8 to 3.3.10, does not involve database changes.
### Start SeaTable server
Now you can start the SeaTable service. Execute the following command in the host server:
```bash
docker exec -d seatable /shared/seatable/scripts/seatable.sh start
```
---
Source: https://admin.seatable.com/upgrade/extra-upgrade-notice/
# Extra upgrade notice
## 6.2
Version v6.2 requires various configuration updates.
If you’re unsure how to apply the required changes or would like us to review your configuration, feel free to reply to [this thread in our community forum](https://forum.seatable.com/t/seatable-v6-2-upgrade-need-help-upgrading/7436).
We’ll be happy to help you update your deployment and ensure the upgrade goes smoothly.
In order to make the upgrade process easier, we have added a script to the release artifact that you'll be downloading as part of the upgrade process.
You can run the script by executing the following command:
```bash
cd /opt/seatable-compose
./migrate/migrate_6.1_6.2.sh
```
The script can be executed multiple times.
You can use this mechanism to check whether you've already migrated all required configuration settings and removed the deprecated configuration files.
In addition, the script creates a backup of the whole `conf/` directory inside `/opt/seatable-server/seatable/` at the beginning of every execution.
The script handles the following steps **automatically**:
- Moving the `SECRET_KEY` variable from `dtable_web_settings.py` to the `.env` file
- Cleaning up unused configuration settings from `dtable_web_settings.py`
In addition, the script checks your current configuration files and lists required **manual changes**:
- The configuration files `dtable-api-gateway.conf`, `dtable-db.conf`, `dtable-events.conf`, `dtable-storage-server.conf` and `dtable_server_config.json` have been **deprecated** and **must be removed**
- Any non-default settings must be **migrated to environment variables**
- If you haven't modified the configuration files, there's no need to set additional environment variables
- If you've enabled S3 storage for base snapshots and assets, you'll need to migrate these configuration settings to environment variables
- If you've enabled SeaTable AI, the LLM provider configuration must be migrated into the new `seatable_config.yaml` configuration file
- This is necessary in order to allow the configuration of _multiple_ LLM providers for different tasks
---
### List of Changes
??? danger "Breaking changes inside SeaTable's Python client"
This breaking change affects systems that make use of the [Python pipeline](../installation/components/python-pipeline.md) in order to run Python scripts (either manually or within automations).
The [Python client](https://developer.seatable.com/python/) included in the `seatable/seatable-python-runner` image has been upgraded to version 4.0.0.
This release includes breaking changes to the format of the `context` object and the response format of the `query()` method.
Please refer to the [forum post](https://forum.seatable.com/t/important-changes-related-to-python-client-in-seatable-6-2/7435) for more information.
??? warning "Multiple configuration files have been deprecated"
The configuration files `dtable-api-gateway.conf`, `dtable-db.conf`, `dtable-events.conf`, `dtable-storage-server.conf` and `dtable_server_config.json` have been **deprecated** and **must be removed** prior to upgrading to SeaTable v6.2.
Any non-default settings must be **migrated to environment variables**
If you haven't modified the configuration files, there's no need to set additional environment variables.
You can find more information on the page for each individual component:
- [api-gateway](../configuration/components/dtable-api-gateway.md)
- [dtable-db](../configuration/components/dtable-db.md)
- [dtable-events](../configuration/components/dtable-events.md)
- [dtable-server](../configuration/components/dtable-server.md)
- [dtable-storage-server](../configuration/components/dtable-storage-server.md)
??? warning "Configuration of email settings inside the configuration file is deprecated"
The configuration of email settings inside the `dtable_web_settings.py` config file has been deprecated.
Please switch to **environment variable**-based configuration instead.
You can find more detailed information in this [article](../configuration/sending-email.md).
??? warning "S3 configuration must be migrated to environment variables"
The configuration of S3 bucket names and credentials inside the configuration files has been deprecated.
Please switch to **environment variable**-based configuration instead.
You can find more detailed information in this [article](../installation/advanced/s3.md).
??? warning "S3 configuration requires an additional bucket"
If you're using S3 to store bases, files and pictures, you'll now have to configure an additional bucket for user avatars.
This can be achieved by setting the `S3_AVATAR_BUCKET` environment variable inside your `.env` file.
Please note that this bucket must be publicly accessible via HTTP(S) since the user avatars are loaded directly from this bucket.
You can find more detailed information in this [article](../installation/advanced/s3.md).
??? warning "LLM provider configuration must be migrated to `seatable_config.yaml`"
If you've deployed [SeaTable AI](../installation/components/seatable-ai.md) alongside SeaTable, you'll now have to migrate the LLM provider configuration
to the new `seatable_config.yaml` config file. This is required since SeaTable AI now supports multiple LLM providers.
You can find more detailed information in this [article](../installation/components/seatable-ai.md#llm-provider-configuration).
??? warning "Configuration of base with custom templates must be migrated to environment variables"
The configuration of a custom base that can be used to define [base templates](../customization/templates.md) inside `dtable_web_settings.py` has been deprecated.
Please switch to **environment variable**-based configuration instead.
You can find more detailed information in this [article](../customization/templates.md).
??? warning "Included n8n deployment: PostgreSQL 11 -> 16"
The following section is only relevant if you have deployed n8n alongside SeaTable using the included `n8n.yml` file.
We've upgraded the PostgreSQL version of the documented n8n deployment from version 11 to version 16.
This requires dumping and restoring your PostgreSQL database **before** running the upgrade.
Please follow the steps outlined in the [PostgreSQL docs](https://www.postgresql.org/docs/current/upgrading.html).
??? info "Change to the quota configuration for Python scripts"
The `scripts_running_limit` quota has been renamed to `scripts_running_limit_per_user`.
Please note that your installation is only affected if you've explicitly configured user roles and set the `scripts_running_limit` quota.
As a result, this quota now applies _per user_, while the total quota within a team will be shared across all team users.
Please refer to [Roles and Permissions](../configuration/roles-and-permissions.md) for more information on all quotas.
## 6.1
Several Docker image tags have been updated to newer versions. These changes are applied automatically when you pull the latest images. Remember to also update your [plugins](../configuration/plugins.md).
??? warning "Python Pipeline requires explicit activation"
Starting with version 6.1, the default value for `ENABLE_PYTHON_SCRIPT` has been changed from `true` to `false`. If you use the Python Pipeline, you must ensure that `ENABLE_PYTHON_SCRIPT=true` is set in your `/opt/seatable-compose/.env` file. Without this setting, Python script execution will be disabled after the upgrade.
## 6.0
**No special steps are required for this upgrade.**
Most services received updated Docker image tags. For example, MariaDB was upgraded from version 11.4 to 11.8. These updates run smoothly and do not require any changes on your side.
??? info "AI-Powered Automations Require Additional Container"
Starting with SeaTable 6.0, AI-powered automations are available as an optional new feature. To enable this functionality, you must add the `seatable-ai` container to your existing SeaTable installation. The container handles all AI-related processing tasks. For installation and configuration details, see [seatable-ai](../installation/components/seatable-ai.md).
??? info "Assignment of IPv6 addresses to containers"
We updated the Caddy configuration to enable containers to receive proper IPv6 addresses, enhancing logging accuracy and network compatibility. If your server has IPv6 disabled, Docker containers may fail to start. In that case, set `ENABLE_IPV6=false` in your `.env` file to disable IPv6 support.
[Read more about IPv6 and Docker](../installation/advanced/ipv6-support.md)
## 5.3
SeaTable v5.3 introduces several significant changes. To make the transition as smooth as possible, we’ve provided a script that handles most of the work for you. Simply run the script to get started.
```bash
bash /opt/seatable-compose/migrate/migrate_5.2_5.3.sh
```
Of course, you can skip this script and make the changes manually. The following sections explain each change in detail, but this approach requires a deeper understanding of SeaTable and Docker.
??? warning "Centralized secret for secure communication"
SeaTable uses a **JWT secret** for secure communication between the SeaTable components: `dtable-web`, `dtable-server` and `dtable-db`.
Before v5.3, this secret was stored in `dtable_web_settings.py` and `dtable_server_config.json`.
Starting with v5.3, this **JWT secret** should be provided via environment variable `JWT_PRIVATE_KEY` in your `/opt/seatable-compose/.env` file.
=== "Script (easy way)"
Execute the migration script below; you only need to run it once.
```bash
bash /opt/seatable-compose/migrate/migrate_5.2_5.3.sh
```
=== "Manual"
- Retrieve the value of `private_key` from `dtable_server_config.json`.
- Add the environment variable `JWT_PRIVATE_KEY=xxx` to your .env file.
- Remove the `private_key` entry from `dtable_server_config.json`.
- Remove the `DTABLE_PRIVATE_KEY` entry from `dtable_web_settings.py`.
??? warning "Centralized MariaDB and Redis configuration"
Starting with version 5.3, SeaTable no longer stores database and Redis credentials in configuration files, but centrally as environment variables. This eliminates redundant configuration settings and makes the configuration files much smaller.
=== "Script (easy way)"
Execute the migration script below; **you only need to run it once**.
```bash
bash /opt/seatable-compose/migrate/migrate_5.2_5.3.sh
```
=== "Manual"
- Open `/opt/seatable-compose/.env` and rename the variable `SEATABLE_MYSQL_ROOT_PASSWORD` to `MARIADB_PASSWORD`.
- Open `/opt/seatable-server/seatable/conf/dtable-events.conf` and remove the entire `[DATABASE]` and `[REDIS]` sections.
- Open `/opt/seatable-server/seatable/conf/dtable_server_config.json` and remove the three lines with `redis_` and the five lines related to `mariadb` (host, user, password, database, port).
- Open `/opt/seatable-server/seatable/conf/dtable_web_settings.py` and remove the entire blocks for `DATABASES = {...}` and `CACHES = {...}`.
- Open `/opt/seatable-server/seatable/conf/seafile.conf` and remove the entire `[database]` section.
In most cases the `dtable_server_config.json` should now only contain `{}`.
??? warning "Mandatory API Gateway in Nginx"
Starting with version 5.3, the SeaTable API Gateway is used to handle all base loading and websocket connections. This requires significant changes to the nginx configuration file.
Due to the complexity and potential for errors, we have decided to provide the nginx configuration file together with the yml files and to mount the configuration into the container.
=== "Mount configuration file (easy way)"
You don't have to do anything. The file `/opt/seatable-compose/config/seatable-nginx.conf` will be mounted to the container.
The old configuration file located at `/opt/seatable-server/seatable/config/nginx.conf` is no longer used and can be removed.
=== "Manual"
- Remove or comment out the volume mount of the nginx configuration from `seatable-server.yml`. Please note that changes to the .yml files are overwritten with the next update. Create a `custom-xxx.yml` file instead.
- Remove the locations `/dtable-db` and `dtable-server`
- Change the location `/socket.io` to `/api-gateway/socket.io/`, and update `http://dtable_servers` to `http://127.0.0.1:7780/socket.io/`
It should look like this:
```conf
# OLD:
#location /socket.io {
# proxy_pass http://dtable_servers;
# NEW:
location /api-gateway/socket.io/ {
proxy_pass http://127.0.0.1:7780/socket.io/;
```
??? info "Migration of comments"
Before 5.3, comments in the base and universal app were handled separately. With 5.3, these comments are merged.
After starting the SeaTable container, you need to run this command *once* to migrate the comments. Don't re-execute it, otherwise your comments will be merged twice.
First enter the docker container.
```bash
docker exec -it seatable-server bash
```
Then merge the comments.
```bash
cd /opt/seatable/seatable-server-latest/dtable-web
seatable.sh python-env manage.py merge_app_comments_to_base
```
??? info "Database Cleanup"
With 5.3, SeaTable automatically enables periodic database cleanup tasks **for new installations** .
This behavior is deliberately not enabled for existing installations.
However, we strongly recommend enabling these tasks to ensure that your database stays performant. It also prevents your server from running out of disk space.
You can achieve this by setting the following option in `/opt/seatable-server/seatable/conf/dtable-events.conf`:
```ini
[CLEAN DB]
enabled = true
```
Please refer to [this document](../configuration/components/dtable-events.md#clean-db) for detailed information on the possible configuration options.
??? info "ccnet.conf is obsolete"
The configuration file `ccnet.conf` is no longer necessary and can be removed.
=== "Script (Easy Way)"
Execute the migration script below; you only need to run it once.
```bash
bash /opt/seatable-compose/migrate/migrate_5.2_5.3.sh
```
=== "Manual"
Remove the configuration file `/opt/seatable-server/seatable/conf/ccnet.conf`.
??? info "New Report Design plugin"
We've developed a new report design plugin, which requires an additional Docker container on your SeaTable server. For installation, follow the instructions available [here](../installation/components/seadoc.md).
??? info "Maps Plugin utilizes two API Keys"
The Google Maps Plugin now uses two separate Google API keys instead of one. Please refer to the [documentation for further details](../configuration/plugins.md#map-plugin).
## 5.2
??? warning "From Two to One: Redis Unifies Caching, Retiring Memcached"
Starting with version 5.2, Redis replaces Memcached as the default cache. Memcached has been removed from the `seatable-server.yml` file in [seatable-release](https://github.com/seatable/seatable-release).
This reduces the number of required caching containers from two to one.
**The following changes are required, if you're upgrading SeaTable to version 5.2**
Updating your caching configuration in `/opt/seatable-server/seatable/conf/dtable_web_settings.py`:
Replace this:
```py
CACHES = {
'default': {
'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
'LOCATION': 'memcached',
},
'locmem': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
}
COMPRESS_CACHE_BACKEND = 'locmem'
```
With this:
```py
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://redis:6379',
}
}
```
- Remove the line with `COMPRESS_CACHE_BACKEND`.
- Adjust `redis://redis:6379` if your Redis container name or port differ. (`redis://:`)
Restart SeaTable:
```bash
docker exec -it seatable-server bash
seatable.sh restart # Run inside the container
```
If the Memcached container is still running, you can now stop it and remove it.
```bash
docker stop memcached
```
??? warning "S3 with Memcached"
If you're using S3 object storage for files and pictures AND have Memcached configured in your `seafile.conf` file, it is crucial that you update your configuration. Otherwise you can ignore this notice.
Please follow the instructions in our help article about [caching for S3](../installation/advanced/s3.md#s3-for-files-and-pictures).
??? info "New Snapshot and Backup Retention Strategy"
With version 5.2, SeaTable introduces a tiered retention strategy for Big Data Backups and Base Snapshots. While updating your settings is optional, it's recommended to take advantage of the new features. You can find the new options in:
- [dtable-db.conf](../configuration/components/dtable-db.md)
- [dtable-storage-server.conf](../configuration/components/dtable-storage-server.md)
??? info "New Whiteboard plugin"
The Excalidraw-based whiteboard plugin introduced in v5.0 was deprecated and removed in v5.3. A new whiteboard plugin using [tldraw](https://tldraw.dev) has been developed, which requires an additional Docker container on your SeaTable server.
For installation, follow the instructions available [here](../installation/components/whiteboard.md). You can easily copy and paste your drawings from the old plugin to the new one. If you have any problems, please report at the [forum](https://forum.seatable.com).
## 5.1
There are no version-specific changes required.
## 5.0
??? warning "API gateway mandatory for external links and big data"
Starting with version 5.0, all requests for external links, external view links or big data views are routed through the API gateway. If you haven't configured the API gateway with version 4.4, you need to do so now for version 5.0.
To configure the API gateway, add the following location block to your `/opt/seatable-server/seatable/conf/nginx.conf` file. Insert this section at the end of the configuration file, just before the final closing curl bracket:
```sh
location /api-gateway/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
return 204;
}
proxy_pass http://127.0.0.1:7780/;
proxy_redirect off;
proxy_set_header Host $http_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;
proxy_set_header X-Forwarded-Proto $scheme;
access_log /opt/nginx-logs/api-gateway.access.log seatableformat;
error_log /opt/nginx-logs/api-gateway.error.log;
}
```
Afterwards check your nginx configuration file for syntax errors and then restart nginx.
```bash
docker exec seatable-server nginx -t
docker exec seatable-server nginx -s reload
```
??? info "Force usage of API gateway endpoints"
The following configuration is optional and can be omitted if you have no issues with API performance, rate limits, and resources. Yet, we recommend using the new `/api-gateway/` endpoints for faster responses and reduced workload on your SeaTable Server.
To enforce redirection of the `List Rows` and `Get Row` calls to the API gateway, append the following codeblock to your `dtable_server_config.json` file:
```json
"redirect_list_rows_api": true,
"dtable_web_service_url": "https://seatable.example.com/"
```
Replace `seatable.example.com` with your SeaTable Server hostname (include the trailing '/').
Afterwards, restart SeaTable with:
```bash
docker exec -it seatable-server /shared/seatable/scripts/seatable.sh restart
```
## 4.4
??? warning "Migration to storage server required"
**Important:** This change applies only to users whose initial installed SeaTable Server version was 1.x or 2.x.:
With SeaTable Server version 3.0, a new storage server was introduced, which is the default storage type of bases since 3.0. If you started with version 1.x or 2.x, you might need to migrate some of your bases, because SeaTable will stop supporting the old storage mechanism with version 4.4.
The migration is easy. First, ensure that you have the following setting in your `dtable_web_settings.py`:
```py
NEW_DTABLE_IN_STORAGE_SERVER = True
```
Then, run these commands to migrate your bases:
```sh
# list number of bases that are not stored in storage-server
docker exec -it seatable-server /templates/migrate_bases.sh --list
# migrate 10 bases to storage-server (repeat this command until all bases are migrated)
docker exec -it seatable-server /templates/migrate_bases.sh --migrate 10
```
Afterwards, restart SeaTable with:
```bash
docker exec -it seatable-server /shared/seatable/scripts/seatable.sh restart
```
??? warning "New API gateway"
With this version, we have introduced a new component to SeaTable Server: the API gateway. This optimized API handler is designed to efficiently manage external API requests for base operations. The API gateway is now started by default and requires no additional configuration files. However, you will need to update your nginx configuration to make the new API endpoints, located at `/api-gateway/`, accessible.
To add this new location, please modify your `/opt/seatable-server/seatable/conf/nginx.conf` file. You can add the following section at the end of the configuration file, just before the final closing bracket:
```sh
location /api-gateway/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers "deviceType,token, authorization, content-type";
return 204;
}
proxy_pass http://127.0.0.1:7780/;
proxy_redirect off;
proxy_set_header Host $http_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;
proxy_set_header X-Forwarded-Proto $scheme;
access_log /opt/nginx-logs/api-gateway.access.log seatableformat;
error_log /opt/nginx-logs/api-gateway.error.log;
}
```
Afterwards check your nginx configuration file for syntax errors and restart nginx.
```bash
docker exec seatable-server nginx -t
docker exec seatable-server nginx -s reload
```
??? info "New Docker container for easy backup"
We've added a new backup container to our lineup of components to simplify your backup process. Using Docker, installation is quick and easy. Our selected backup software, [restic](https://restic.net), supports a wide range of backup targets, including S3, Backblaze, local storage, and more. With restic's reliability, your data is secure with every backup.
## 4.3
??? warning "New default setup with multiple predefined yml files"
Version 4.3 introduces a new installation method relying on multiple yml files, an .env file and caddy as new reverse proxy. This setup is more convenient and will be the basis for all future explanations.
It is not mandatory to switch to this new setup but it is recommended. Read this [article for more information](./migrate-seatable-release.md).
??? info "MariaDB container healthchecks"
This help is important if your MariaDB container remains unhealthy after executing `docker compose up -d`. This issue arises specifically if your initial MariaDB version was below 10.6 and you have now upgraded to a newer version. Older versions did not create the required health check user in the local database, causing the health checks to fail.
We have provided a simple script for you to download and create the necessary health check user. Please use the following commands to download and execute it. The script assumes the MariaDB container is running and that you have followed all installation instructions outlined in this manual.
```bash
curl -sSL https://admin.seatable.com/downloads/add_mariadb_healthcheck.sh | bash
```
If you wish to review the script's functionality, simply open it in your browser: [Add MariaDB Healthcheck Script](https://admin.seatable.com/downloads/add_mariadb_healthcheck.sh).
The script essentially adds the user `healthcheck` to the MariaDB database and stores the credentials in a file accessible to the container."
??? info "Django CSRF protection"
Django 4.* has introduced a new check for the origin http header in CSRF verification. It now compares the values of the origin field in HTTP header and the host field in HTTP header. If they are different, an error is triggered.
If you deploy SeaTable behind a proxy, if you use a non-standard port or if you deploy SeaTable in cluster, it is likely that the origin field in HTTP header received by Django and the host field in HTTP header received by Django are different. This mismatch results in a CSRF error.
You can add `CSRF_TRUSTED_ORIGINS` to `dtable_web_settings.py` to solve the problem:
```bash
CSRF_TRUSTED_ORIGINS = ["https://"]
```
## 4.0
??? warning "Big data storage migration needed (Enterprise only)"
Version 4.0 modifies the data format of the backup of big data storage. Compared with previous upgrades, an additional format migration script needs to be run inside the docker:
```bash
# replace seatable if you container image is called differently.
docker exec -it seatable /templates/migrate-dtable-db-backups.sh
```
??? info "Universal App is now enabled by default"
The Enterprise Edition enables the Universal app by default. The option ENABLE_UNIVERSAL_APP is removed from `dtable_web_settings.py`.
??? info "Recycle bin is emptied after 30 days"
SeaTable empties the recycle bin automatically after 30 days. If you want to change this default behaviour, add the following option to your `dtable_web_settings.py`.
```python
TRASH_CLEAN_AFTER_DAYS = 30
```
??? info "New API Limits"
API_THROTTLE_RATES is used to replace the old REST_FRAMEWORK option. Usually the default values of the API_THROTTLE_RATES are good. Change the following values only if need higher limits. Add one of multiple options to your `dtable_web_settings.py`.
```python
API_THROTTLE_RATES = {
'ping': '3000/minute',
'anon': '60/minute',
'user': '3000/minute',
'sync_common_dataset': '60/minute',
'password_reset': '10/minute',
'org-admin': '1000/day',
'app': '1000/minute',
'import': '20/minute', # Limit the rate of API calls for importing via excel/csv
'export': '20/minute', # Limit the rate of export base, table and view
}
```
## 3.0
??? warning "New component: dtable-storage-server"
3.0 adds another component, dtable-storage-server, which provides better performance for persistent storage of bases. A base in SeaTable is saved as a file, which is automatically saved every 5 minutes. In 2.x, this file saved in seaf-server, but seaf-server will keep a version for each save, which will take up a lot of disk space. In 3.0, only one version is actually saved when a snapshot is generated every 24 hours, which saves space. dtable-storage-server is a simple abstract layer of traditional file system and object storage.
1. For new installation, dtable-storage-server.conf will be generated automatically. For upgrade from 2.x, you need to generate the config file manually
```bash
docker exec -d seatable /shared/seatable/scripts/seatable.sh init
```
dtable-storage-server.conf is as follows
```ini
[general]
log_dir = /opt/seatable/logs
temp_file_dir = /tmp/tmp-storage-data
[storage backend]
type = filesystem
path = /opt/seatable/storage-data
[snapshot]
interval = 86400
keep_days = 180
```
2. Add configuration in dtable_web_settings.py so that the newly created bases are saved to the dtable-storage-server, and the old bases are still read and written from seaf-server.
In dtable_web_settings.py
```python
NEW_DTABLE_IN_STORAGE_SERVER = True
```
3. Enterprise edition needs to add configuration items in dtable-db.conf to automatically back up the archived data in the dtable-db.
In `dtable-db.conf`
```ini
[backup]
dtable_storage_server_url = http://127.0.0.1:6666
backup_interval = 1440
keep_backup_num = 3
```
4. Migrate bases to storage server
Run these commands to list and migrate your bases to the new storage server.
```sh
# list number of bases that are not stored in storage-server
docker exec -it seatable-server /templates/migrate_bases.sh --list
# migrate 10 bases to storage-server (repeat this command until all bases are migrated)
docker exec -it seatable-server /templates/migrate_bases.sh --migrate 10
```
## 2.7
??? info "Embed into iframes"
The configuration of the embedded base to other webpages (iframe mode) needs to be modified as follows
In dtable_web_settings.py
```python
SESSION_COOKIE_SAMESITE = None
|
V
SESSION_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SAMESITE = None
|
V
CSRF_COOKIE_SAMESITE = 'None'
```
## 2.3
??? warning "Configuration changes of dtable-db"
In 2.3 version, we made a small change to dtable-db configuration. If you're upgrading from older versions, you have to manually add below option to conf/dtable-db.conf:
```ini
[general]
......
log_dir = /shared/seatable/logs
......
```
It's also suggested to change the `total_cache_size` option to a larger value (e.g. 500MB, depending on how much memory you have):
```ini
[dtable cache]
......
total_cache_size = 500
......
```
You also need to add access information to dtable-server MySQL database. (You have to change below options based on your conf/dtable-server.json)
```ini
[database]
host = 127.0.0.1
user = root
password = mypass
db_name = dtable
```
Add `DTABLE_DB_URL` to dtable_web_settings.py
```python
DTABLE_DB_URL = 'https:///dtable-db/'
```
Add dtable-db configuration to nginx.conf
```nginx
location /dtable-db/ {
proxy_pass http://127.0.0.1:7777/;
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;
proxy_set_header X-Forwarded-Proto $scheme;
access_log /opt/nginx-logs/dtable-db.access.log seatableformat;
error_log /opt/nginx-logs/dtable-db.error.log;
}
```
## 2.1
??? warning "New component: dtable-db"
2.1 add another component dtable-db, which is used to provide SQL query API (more features will be provided based on this component). For newly installation, the config file will be generated automatically. For upgrade from 2.0, you need to add the config file manually.
Add a new file conf/dtable-db.conf with the following contents and modify `private_key` according to your instance:
```ini
[general]
host = 127.0.0.1
port = 7777
[storage]
data_dir = /opt/seatable/db-data
[dtable cache]
private_key = "my private key"
dtable_server_url = "http://127.0.0.1:5000"
expire_time = 600
total_cache_size = 1
clean_cache_interval = 300
```
The value of `private_key` should be the same as the value in `dtable_server_config.json`.
dtable_server_url should be http://127.0.0.1:5000. You don't need to modify the value.
---
## Migrations
Source: https://admin.seatable.com/upgrade/migrate-seatable-editions/
# Migrate between SeaTable Editions
The migration between SeaTable Enterprise Edition and SeaTable Developer Edition is easy and possible at any time. Please make sure that you only migrate between the same major and minor versions:
- 3.3.7 Enterprise Edition :material-chevron-double-right: 3.3.0 Developer Edition is :white_check_mark:
- 3.2.0 Developer Edition :material-chevron-double-right: 3.2.6 Enterprise Edition is :white_check_mark:
- 3.3.7 Enterprise Edition :material-chevron-double-right: 3.4.0 Developer Edition is :red_square:
- 3.2.0 Developer Edition :material-chevron-double-right: 3.3.7 Enterprise Edition is :red_square:
You can find the available images and their versions at :material-docker: docker hub:
- [Available Enterprise Editions](https://hub.docker.com/r/seatable/seatable-enterprise/tags)
- [Available Developer Editions](https://hub.docker.com/r/seatable/seatable-developer/tags)
To protect your data, it is strongly recommended to back up the database prior to the migration. See the section on [backup and recovery](../maintenance/backup-recovery.md) for details.
## Migration
Basically for the migration only two things are important:
- provide a seatable server license (if necessary)
- switch the used docker image
After a restart of the docker containers, SeaTable takes care of the rest. So let see what you have to do.
??? tip "Migrate from Enterprise Edition to Developer Edition"
## Enterprise to Developer Edition
### Stop SeaTable Server
Stop all containers that are currently running.
```bash
cd /opt/seatable-compose && \
docker compose down
```
### Switch images
Open your `/opt/seatable-compose/.env` file and add this line to use the SeaTable developer image.
Make sure to replace `latest` with the correct version as described at the beginning of this article.
```bash
SEATABLE_IMAGE='seatable/seatable-developer:latest'
```
### Restart SeaTable Server
Just copy and paste these commands to restart seatable.
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
??? success "Migrate from Developer Edition to Enterprise Edition"
## Developer to Enterprise Edition
### Stop SeaTable Server
Stop all containers that are currently running.
```bash
cd /opt/seatable-compose && \
docker compose down
```
### Modify your .env file
Open your .env file and search for the definition of SEATABLE_IMAGE. It should point to `seatable/seatable-developer`. Either remove this line or add the correct SeaTable Enterprise Edition.
### Provide the seatable-server licence file
Save the `seatable-license.txt` to `/opt/seatable-compose`.
### Restart SeaTable Server
Just copy and paste these commands to restart seatable.
```bash
cd /opt/seatable-compose && \
docker compose up -d
```
---
Source: https://admin.seatable.com/upgrade/migrate-seatable-release/
# Migrate to new installation method
To bring your SeaTable Server into the /opt/seatable-compose form used by version 4.3.10 and greater, the following needs to be done:
- Change directory structure
- Change container names
- Modify configuration files
- Remove Python Runner, FAAS Scheduler and OnlyOffice (will be activated again after the migration)
A key part of this migration is the change in how MariaDB and Redis connections are configured. Beginning with version 5.3, MariaDB and Redis are now managed through the `.env` file, so you can remove these entries from the configuration files.
Additionally, you will need to add new variables to the `.env` file.
Please read the [Extra upgrade notices](../upgrade/extra-upgrade-notice.md) carefully.
Updating SeaTable Server might entail changes to your database. To make sure your data is protected in any case, we recommend to create a backup/dump of your databases before the update. See [backup and recovery](../maintenance/backup-recovery.md) for more details.
## Required steps
### 1. Stop all containers
Stop all containers (not only SeaTable) but also Python Runner, FAAS Scheduler and OnlyOffice.
```bash
cd /opt/seatable
docker compose down
```
The usage of `docker-compose` (with - in the command) is not supported any longer. Please switch to the new command `docker compose`. Please refer to the [offical install instructions](https://docs.docker.com/compose/install/). For Debian and Ubuntu, this should be sufficient:
```bash
apt update && \
apt remove docker-compose
curl -fsSL get.docker.com | bash
```
Check for running containers with `docker container list`. Execute `docker stop ` for containers still running.
### 2. Remove Python Pipeline and OnlyOffice
If you installed OnlyOffice, Python Runner or FAAS Scheduler, you should remove the associated folders.
```bash
rm -r /opt/onlyoffice
rm -r /opt/seatable-python-runner
rm -r /opt/seatable-faas-scheduler
```
### 3. Get password and other values from docker-compose.yml
Open up your current docker-compose.yml with the editor of your choice (such as vim or nano) and note these three values:
- MYSQL_ROOT_PASSWORD
- SEATABLE_SERVER_HOSTNAME
- TIME_ZONE
Rename docker-compose.yml to docker-compose.old so that it is no longer used:
```bash
mv /opt/seatable/docker-compose.yml /opt/seatable/docker-compose.old
```
### 4. Create new .env file.
Copy and paste these commands to download the new installation method.
```bash
mkdir /opt/seatable-compose && \
cd /opt/seatable-compose && \
wget -c https://github.com/seatable/seatable-release/releases/latest/download/seatable-compose.tar.gz \
-O - | tar -xz -C /opt/seatable-compose && \
cp -n .env-release .env
```
Open `/opt/seatable-compose/.env` with your editor of choice and assign the values noted in 3. to these three variable:
- TIME_ZONE
- SEATABLE_MYSQL_ROOT_PASSWORD
- SEATABLE_SERVER_HOSTNAME
Additionally, the two variables SEATABLE_ADMIN_EMAIL and SEATABLE_ADMIN_PASSWORD must be specified. Currently the values are only used during the initial installation but this might change in the future.
If you are using SeaTable Developer Edition instead of Enterprise Edition, add the following parameter to your `.env` file. This overwrites the used SeaTable Docker image.
``` python
SEATABLE_IMAGE='seatable/seatable-developer:latest' # (1)!
```bash
1. Instead of using the latest tag, you can select any specific version from [https://hub.docker.com/r/seatable/seatable-developer/tags](https://hub.docker.com/r/seatable/seatable-developer/tags).
### 5. Move the license file
This step is solely required for SeaTable Enterprise Edition. You can skip this step for **SeaTable Developer Edition** and just create an empty file at `/opt/seatable-compose/seatable-license.txt`.
Copy your existing seatable-license.txt to this `/opt/seatable-compose` folder:
```bash
cp /opt/seatable/seatable-data/seatable-license.txt /opt/seatable-compose/
```
### 6. Move two folders
Move two folders, which contain Docker volumes, to new paths.
```bash
mv /opt/seatable/mysql-data /opt/mariadb
mv /opt/seatable/seatable-data /opt/seatable-server
```
### 7. Change database container in configuration file
Previously, the mariadb container was named **db**. In the new deployment method, we call this container by its full name: **mariadb**. Consequently, we must update the configuration files so as to enable SeaTable to find the SQL-database and connect to it.
All changes must be done in `/opt/seatable-server/seatable/conf`. Update the following configuration files as described with your editor of choice.
```bash
cd /opt/seatable-server/seatable/conf
nano ccnet.conf
# replace ccnet.conf with the other configuration file names and update all files
```
#### ccnet.conf
```bash
HOST = db # change to mariadb
```
#### dtable-db.conf
No change needed.
#### dtable-events.conf
```bash
[DATABASE]
host = db # change to mariadb
```
#### dtable_server_config.json
```bash
"host": "db" # change to mariadb
```
#### dtable-storage-server.conf
No change needed.
#### dtable_web_settings.py
```bash
DATABASES = {
'default': {
...
'HOST': 'db' # change to mariadb
...
}
}
SEATABLE_FAAS_URL = 'https://seatable-faas.example.com' # if you had the Python Runner and FAAS Scheduler configured, remove this variable entirely
SEATABLE_FAAS_AUTH_TOKEN = 'secret_string' # if you had the Python Runner and FAAS Scheduler configured, remove this variable entirely
ENABLE_ONLYOFFICE = False # if you had OnlyOffice configured, remove this variable entirely
ONLYOFFICE_APIJS_URL = "https://seatable.example.com/onlyofficeds/web-apps/apps/api/documents/api.js" # if you had OnlyOffice configured, remove this variable entirely
ONLYOFFICE_FILE_EXTENSION = ('doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'odt', 'fodt', 'odp', 'fodp', 'ods', 'fods', 'csv', 'ppsx', 'pps') # if you had OnlyOffice configured, remove this variable entirely
ONLYOFFICE_JWT_SECRET = 'asecretjwttoken' # if you had OnlyOffice configured, remove this variable entirely
```
#### seafile.conf
```bash
host = db # change to mariadb
```
### 8. Remove HTTPS from nginx
In this step, the configuration of nginx, which is included in the SeaTable Server container, must be changed to account for the addition of **caddy** in the new deployment method to take care of TLS termination and certificate management. Specifically, this requires that nginx no longer listens on port 443 (HTTPS), but only on port 80 (HTTP).
First let's make a copy of your current nginx file to make sure that we have a safety net just in case.
```bash
cp /opt/seatable-server/seatable/conf/nginx.conf /opt/seatable-server/seatable/conf/nginx.backup
```
Now we want to make these changes in the `nginx.conf`:
1. We want to remove the server block which is responsible for listening to port **80** (or change it to another port)
2. We want to update the second server block and change port **443** to **80**
3. We want to remove all lines that start with **ssl\_**
You can do this with these commands:
```bash
cd /opt/seatable-server/seatable/conf
sed -i 's/ listen 80/ listen 9999/' ./nginx.conf
sed -i 's/ listen 443 ssl/ listen 80/' ./nginx.conf
sed -i '/^[[:space:]]*ssl_/d' ./nginx.conf
```
### 9. Start your SeaTable Server
Now the migration is complete and it is time to start SeaTable Server again.
```bash
cd /opt/seatable-compose
docker compose up -d
```
Be patient and give the containers time to start. Then open your browser and check if you can access your SeaTable Server.
If your SeaTable Server does not react as expected, check the [FAQ/Troubleshooting](../installation/faq.md) article. In case your mariadb container stays unhealthy, check the [Extra upgrade notices for version 4.3](https://admin.seatable.com/upgrade/extra-upgrade-notice/).
Please note that additional components like the Python Pipeline or an integrated Online Editor will not be working at this point.
### 10. Add additional components
To setup the Python Pipeline or an Online Editor, please follow the manuals in the [Installation](https://admin.seatable.com/installation/deployment-approach.md) section.
---
## Maintenance
Source: https://admin.seatable.com/maintenance/restart-seatable/
# Restarting the SeaTable service
Changes in the configuration files, require a restart of the SeaTable service.
## Method 1: Restart from outside the container
To restart the SeaTable service directly from your host command line, use:
```bash
docker exec seatable-server /opt/seatable/scripts/seatable.sh
```
This command runs the SeaTable startup script inside the container, managing all necessary service processes. You must specify the full path to `seatable.sh` because the Docker exec command does not use the container’s `PATH` environment variable by default.
## Method 2: Restart from inside the container
Alternatively, you can open an interactive shell inside the container and run the script manually:
```bash
docker exec -it seatable-server bash
seatable.sh
exit
```
When using an interactive shell, you do not need to specify the full path to `seatable.sh` because the container’s `PATH` is available. After restarting the service, type `exit` to leave the container shell.
# Restarting the docker container
Alternatively, you can restart the complete SeaTable Docker container. This is useful if you need to ensure all processes and services inside the container are refreshed.
You need to navigate to your SeaTable compose directory (commonly `/opt/seatable-compose`), then run:
```bash
/opt/seatable-compose
docker stop seatable-server
docker compose up -d
```
This will stop the SeaTable container and then restart it in detached mode. All related services defined in your `docker-compose.yml` will also be managed according to your configuration.
---
Source: https://admin.seatable.com/maintenance/backup-recovery/
# Backup and Recovery
If you decide to run your own SeaTable Server, it is essential to ensure that you have a backup in place.
To understand what needs to be backed up, you must first understand the architecture of a SeaTable Server. If you have not yet read the [relevant chapter](../introduction/architecture.md), please do so now.
For single-node servers, we offer a [user-friendly backup container](../installation/components/restic.md) that simplifies the process. Even with this tool, it is important to read this article to gain a thorough understanding of SeaTable backup procedures.
This article details what should and must be included in your backup, providing you with the knowledge to create your own backup procedure.
These instructions only cover the backup and restore of the SeaTable Server. Other tools or services on the same host (e.g. n8n, monitoring, reverse proxies) must be backed up separately. The steps assume a standard installation; if you have custom paths, containers, or configs, adjust them accordingly.
## Data and folder structure
If you set up your SeaTable server according to this manual, your server should have a folder structure similar to the following.
```text
/opt
├── caddy
│ ├── ...
├── containerd
│ ├── ...
├── mariadb
│ ├── ...
├── seatable-compose
│ ├── .env
│ ├── caddy.yml
│ ├── ...
└── seatable-server
├── nginx-logs
├── seatable
│ ├── ccnet
│ ├── conf
│ ├── db-data
│ ├── logs
│ ├── pids
│ ├── scripts
│ ├── seafile-data
│ ├── seahub-data
│ ├── seatable-license.txt
│ └── storage-data
└── ssl
```
There are generally four parts of data you have to save to keep your data secure.
- MariaDB database
- SeaTable base data (including Big Data)
- Configuration files with private keys
- Credentials and deployment settings
Let us clarify where you find which content and how we should backup them.
It's impossible to describe all variations of possible custom configurations. Therefore, keep the following rule in mind: if you made custom changes, you must check if they need to be included in the backup. For example, if you added custom certificates in the Caddy folder, ensure these certificates are included in your backup.
## What to backup?
### Mariadb database
A common misunderstanding is the assumption that the content of SeaTable bases is stored in the MariaDB container. This is not the case. Refer to the chapter about [SeaTable architecture](../introduction/architecture.md) for more details.
SeaTable creates three databases in the `mariadb` Docker container, storing these kind of data types:
- **ccnet_db:** User accounts, Groups and team assignment.
- **seafile_db:** Workspace definitions and versioning information for the files and images.
- **dtable_db:** Meta-information for the bases, statistic and log information and operation log
The mariadb container persists the database information in the directory `/opt/mariadb` but instead of saving this directory you should create database dumps. Use the following commands to create such dump files.
```bash
# you can copy these commands to a shell script and execute this via a cronjob.
# Beware that this method will expose your mysql password in the process list
# and shell history of the docker host.
source /opt/seatable-compose/.env
mkdir -p /opt/seatable-backup && cd /opt/seatable-backup
docker exec -it mariadb mariadb-dump -u root -p${MARIADB_PASSWORD} --opt ccnet_db > ./ccnet_db.sql
docker exec -it mariadb mariadb-dump -u root -p${MARIADB_PASSWORD} --opt seafile_db > ./seafile_db.sql
docker exec -it mariadb mariadb-dump -u root -p${MARIADB_PASSWORD} --opt dtable_db > ./dtable_db.sql
```
If you want to execute the `docker ... mariadb-dump` command directly as a cronjob, you have to remove the parameters `-it`. Otherwise you will only create an empty dump file.
Sometimes cronjob has problems with the path and `docker` is not sufficient.
SeaTable stores various logs in the database, which can cause your database dump to grow significantly, especially for the tables `operation_log`, `delete_operation_log`, `session_log` and `activities`.
To manage this, you have two effective options:
- Use Seatable’s built-in function to regularly [clean old log entries](./database-cleanup.md), keeping your database size manageable without losing recent data.
- During backups, use the `--ignore-table` parameter to split your dump into two parts: a core dump excluding large log tables, and a separate dump for the log tables.
This strategy reduces dump size and enables selective restoration of core data and logs as needed.
### Base content
Inside the `/opt/seatable-server/seatable` directory, there are multiple folders containing user data, most importantly, the content of all SeaTable bases. Each base has a unique ID (base_uuid) used in the folder structure. The three folders that must be included in the backup are:
- **storage-data**: contains base data, base snapshots and big data dumps.
- **seafile-data**: contains uploaded files for file and image columns.
- **seahub-data**: contains data used by web front-end, such as avatars
The `db-data` directory contains big data content in a sql-like database structure. **It is not recommended to save this folder.** Instead the big data content is dumped to the storage-data folder automatically every 24 hours by default. Therefore it is already part of your backup.
1. To backup big data more often, change the [dtable-db settings](/configuration/components/dtable-db).
2. To force the dump of big data you could execute the following command:
```sh
docker exec -it seatable-server /opt/seatable/scripts/seatable.sh backup-all
```
### Configuration files
The `conf` directory contains all the configuration files for your SeaTable Server. While these files are not mandatory for restoring your server, they simplify the process. Therefore, we recommend including the `conf` folder in your backup.
### Credentials & deployment settings
The `/opt/seatable-compose/` directory contains your `.env` file with secrets and your SeaTable license file. Including this directory in your backup is essential.
## Manual backup process
In MariaDB 11, the commands `mysql` and `mysqldump` have been deprecated. Please use `mariadb` or `mariadb-dump` instead. Ensure your backup scripts create database dumps correctly.
Now that you understand the theory behind which files and directories need to be backed up, the following script could serve as a good starting point to consolidate all necessary files into the directory `/opt/seatable-backup`. From there, you can choose the backup method that best suits your needs.
```bash
#!/bin/bash
# create the backup directory
mkdir -p /opt/seatable-backup/
# mariadb dumps
source /opt/seatable-compose/.env
cd /opt/seatable-backup
docker exec mariadb mariadb-dump -u root -p${MARIADB_PASSWORD} --opt ccnet_db > ./ccnet_db.sql
docker exec mariadb mariadb-dump -u root -p${MARIADB_PASSWORD} --opt seafile_db > ./seafile_db.sql
docker exec mariadb mariadb-dump -u root -p${MARIADB_PASSWORD} --opt dtable_db > ./dtable_db.sql
# force dump of big data to storage-data folder
docker exec -it seatable-server /opt/seatable/scripts/seatable.sh backup-all
# backup files (exclude unnecessary directories)
rsync -az --exclude 'ccnet' --exclude 'logs' --exclude 'db-data' --exclude 'pids' --exclude 'scripts' /opt/seatable-server/seatable /opt/seatable-backup
rsync -az /opt/seatable-compose /opt/seatable-backup/
```
## Special cases and advanced topics
This section covers typical custom cases and provides additional advanced topics.
??? success "Backup Order: database first or data directory first?"
For larger SeaTable instances, a complete backup may take some time. Therefore, you should consider whether to backup the MariaDB database first and then the data directory, or vice versa. In general, there is no issue with a time difference between the database and data backup. However, if you have to choose, we recommend backing up the database first, followed by the data folder. Here's why:
- If you back up the data directory first, there's a risk that new objects referenced in the MariaDB database may not yet exist in the file system. This could potentially lead to problems, even resulting in base corruption.
- If you back up the database first, you can be confident that all entries in the database reference valid objects.
??? success "S3 Object storage instead of local storage"
If you're using [S3 Object Storage](../installation/advanced/s3.md) instead of local storage, the folders `storage-data` and `seafile-data` aren't stored on the local file system. Instead, all data is stored in four S3 buckets. Three buckets `fs`, `commits` and `blocks` contain assets from file/image column and `storage` contains the base data.
A recommended backup method would be to implement an S3 sync with active versioning and lifecycle management.
??? success "Example of a S3 sync job with rclone"
We have had positive experiences using these `rclone` parameters to synchronize buckets containing millions of objects and terabytes of data. Be sure to customize the command according to your bucket names and rclone configuration.
```bash
rclone sync source:bucket-name target:bucket-name \
--config /opt/rclone.conf \
--stats 30m \
--stats-one-line \
--stats-log-level NOTICE \
--transfers=16 \
--checkers=16 \
--skip-links \
--s3-no-check-bucket \
--log-file="/opt/backup.log" \
--log-level=NOTICE
--size-only
```
??? success "URL Change during restore"
If you restore your SeaTable Server with a new URL, don't forget to execute the [command line tool to update the URL](./domain-change.md). Otherwise assets from the image and file columns will not be accessible.
??? success "Take care to take over the PLUGINS_REPO_ID"
During the initial startup of the SeaTable container, SeaTable writes a variable called `PLUGIN_REPO_ID` to `dtable_web_settings.py`.
This variable represents a hidden library that stores the installation files of the SeaTable plugins. If you delete (commenting is not sufficient) this value from the configuration file, SeaTable will generate a new value upon the next start.
When performing a migration or restore, you have two options: you can either retain the existing value, ensuring that this repository exists in dtable-storage, or you can delete the value from `dtable_web_settings.py` and allow SeaTable to create a new one.
## Restore
The following steps guide you through a complete restore of your SeaTable Server. They assume you are restoring to a fresh server with the backup available at `/opt/seatable-backup/`. If you are restoring to the same server, skip step 1.
### 1. Install a fresh SeaTable Server
Follow the [basic setup](../installation/basic-setup.md) up to and including `docker compose up -d`. Wait for the initial setup to complete successfully, then stop all containers:
```bash
cd /opt/seatable-compose
docker compose down
```
### 2. Restore the databases
Start only MariaDB and wait a few seconds for it to be ready:
```bash
docker compose up -d mariadb
```
Then import the database dumps:
```bash
source /opt/seatable-compose/.env
docker exec -i mariadb mariadb -uroot -p${MARIADB_PASSWORD} ccnet_db < /opt/seatable-backup/ccnet_db.sql
docker exec -i mariadb mariadb -uroot -p${MARIADB_PASSWORD} seafile_db < /opt/seatable-backup/seafile_db.sql
docker exec -i mariadb mariadb -uroot -p${MARIADB_PASSWORD} dtable_db < /opt/seatable-backup/dtable_db.sql
```
### 3. Restore files and configuration
Copy the base data and deployment settings back to their original locations:
```bash
rsync -az /opt/seatable-backup/seatable /opt/seatable-server
rsync -az /opt/seatable-backup/seatable-compose /opt
```
### 4. Start SeaTable and restore Big Data
```bash
cd /opt/seatable-compose
docker compose up -d
docker exec -it seatable-server /opt/seatable/scripts/seatable.sh restore-all
```
The `restore-all` command recreates the Big Data database structure from the dumps in the `storage-data` folder.
### 5. Verify the restore
- Open SeaTable in the browser and log in with your admin account
- Check that bases and their content are accessible
- Verify that file and image columns load correctly
- Open a base with Big Data views and confirm the data is present
If your new server uses a different domain than the original, you must run the [domain change procedure](./domain-change.md) after the restore. Otherwise, assets from file and image columns will not be accessible.
During the initial startup, SeaTable writes a variable called `PLUGIN_REPO_ID` to `dtable_web_settings.py`. This variable references a hidden library that stores plugin installation files.
When restoring, you have two options: either keep the existing value from your backup (ensuring the corresponding repository exists in dtable-storage), or delete the value from `dtable_web_settings.py` and let SeaTable generate a new one on the next start.
---
Source: https://admin.seatable.com/maintenance/database-cleanup/
# Database Cleanup
## Automatic cleanup
Since version 5.3, SeaTable automatically cleans up its database. A background task regularly removes outdated entries from tables that tend to accumulate unnecessary data and cause database bloat. For details on which tables are cleaned and the specific retention periods, refer to the [configuration of dtable-events](../configuration/components/dtable-events.md#clean-db).
Database cleanup is enabled by default for new SeaTable installations (version 5.3 and later). However, if you upgrade an existing system to 5.3, the cleanup feature is not activated automatically. In this case, you need to manually configure the [cleanup in dtable-events](../configuration/components/dtable-events.md#clean-db).
## Background information and manual cleanup
Although SeaTable has a cleanup mechanism for its database, it is not activated by default. Even if you have a small setup, it is recommended that you setup a single cronjob for cleanup to run for example once a week. Otherwise your database will become bigger and bigger. This article explains all the details.
## Why does the database become too big?
The main reason why the SeaTable database grows quickly is due to the storage of the operation log. Every time you change something in a base, this change is stored in the so called operation log. The operation log contains the base, the table, the row and the concrete change. You might imagine how fast this database table gets if such a huge amount of data is stored every time you change something in the database.
```json
{
"op_type": "modify_row",
"table_id": "iFMf",
"row_id": "avAf...",
"updated": {
"s6km": ["91e3...@auth.local"],
"_last_modifier": "1455...@auth.local"
},
"old_row": { "s6km": ["ea3b...6@auth.local"] }
}
```
In addition, every 5 minutes `dtable-server` automatically persists all changes by saving the current version of the base to `dtable-storage-server`. The operation log is therefore a protection against data loss in case that SeaTable server crashes before the base is persisted. As soon as the base is persisted, the main purpose of the operation log is fulfilled.
In addition the operation log is used for the log display inside the base.
Let me summarize, the operation log has two purposes:
1. the operation log protects against data loss in the event that SeaTable Server crashes before the changes are persisted to the json file.
2. the operation log is used for the log/history display inside the base.
Just to give you an idea. At [SeaTable Cloud](https://cloud.seatable.io) we generate up to **1 Gigabyte per day**, mainly driven by the operation log.
## Clean Database Records
SeaTable provides a command to clear records older than the retention period in the seatable database (the default database name is `dtable_db`). The retention period is a good mixture of cleaning up old data and keep enough data for the users.
### Manual execution
If you want to run the command manually, here it is:
```bash
docker exec -it seatable-server /bin/bash
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py clean_db_records
```
The following tables will be cleaned:
| Database table | Table description | Retention period |
| ------------------------------ | --------------------------------------------------------------------------------------------- | ---------------- |
| dtable_snapshots | Snapshots of bases that are not stored in dtable-storage-server | 365 days |
| activities | Aggregated log (based on operation_log) recording row creations, modifications, and deletions | 30 days |
| operation_log | Low level log recording all operations (of dtable-server) | 14 days |
| delete_operation_log | High level log (based on operation_log) recording all row deletions | 30 days |
| dtable_db_op_log | Low level log recording all operations (of dtable-db) | 14 days |
| notifications_usernotification | User notifications on the home page | 30 days |
| dtable_notifications | User notifications inside the bases | 30 days |
| session_log | Low level log recording all user sessions | 30 days |
| auto_rules_task_log | Logs of automation rules | 14 days |
| dtable_app_pages_operation_log | Low level log recording all app operations | 14 days |
### Cronjob
If you want to keep your database small, it is necessary to execute your cleanup on a daily or weekly basis. Generate a bash script like the following, give it execution permission and create a cronjob to run it on a regular basis.
```bash
#!/bin/bash
docker exec seatable-server /opt/seatable/scripts/seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py clean_db_records
```
The cronjob might look like this:
```bash
# clean system (once a week at saturday at 0:20am)
0 20 * * 6 /opt/backup/scripts/system_clean.sh > /opt/backup/logs/system_clean.log
```
## Clean operation_log records more efficiently
If your system becomes really big, you might want to clean up the operation log faster. Therefore a new more efficient and reliable command was added to clear the useless data in the operation_log table after three days. You can add a cron job to run the command every day.
This command has two advantages over the above command:
1. It will make sure all pending operations be applied to the base before clearing the logs.
2. It will clear the logs in small batch, avoiding consuming too much database resource in a short time.
```bash
$ docker exec seatable-server /opt/seatable/scripts/seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py clean_operation_log
```
## Free space occupied by database
Mariadb and MySQL are quite special if it comes to storage usage. Even if you delete data from your database, the storage will not become available. Space that once was occupied by MySQL is blocked.
This becomes problematic if you database becomes huge, because you never cleaned the operation log and now the disk space is full. There are basically two ways to solve this problem.
### Check your database size
Login into your SQL command line of your mariadb server. Now execute the following commands to get the size of your databases
```bash
SELECT table_schema AS "Database", ROUND(SUM(data_length + index_length) / 1024 / 1024 / 1024, 2) AS "Size (GB)" FROM information_schema.TABLES GROUP BY table_schema;
```
The result may look like this:
```bash
+--------------------+-----------+
| Database | Size (GB) |
+--------------------+-----------+
| ccnet_db | 0.04 |
| dtable_db | 32.31 |
| information_schema | 0.00 |
| seafile_db | 0.07 |
+--------------------+-----------+
4 rows in set (0.005 sec)
```
To get the size of the tables inside `dtable_db` execute one of these commands:
```bash
# get number of rows of the tables inside dtable_db
SELECT table_name, table_rows FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'dtable_db';
# get size of the tables inside dtable_db
SELECT table_name AS "Table", ROUND(((data_length + index_length) / 1024 / 1024), 2) AS "Size (MB)" FROM information_schema.TABLES WHERE table_schema = "dtable_db";
```
To delete all entries from the operation log older than 14 days, you can execute this command:
```bash
DELETE FROM `operation_log` WHERE `op_time` < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 14 DAY))*1000
```
Deleting entries from the `operation_log` table doesn't automatically free up disk space. To reclaim space, you need to delete and recreate the table. Here are two options to achieve this:
### Preparation Steps:
1. **Stop SeaTable:** It's recommended to stop SeaTable before proceeding to prevent new entries in the `operation_log`.
2. **Keep MariaDB Running:** Ensure the MariaDB container is running to access the database command line.
3. **Create a Backup:** Always create a database backup before direct database operations to mitigate risks.
### Option 1: Create a Copy and Rename the Table
This method requires sufficient disk space to create a duplicate of the existing operation log.
```sql
USE dtable_db;
CREATE TABLE operation_log_copy AS SELECT * FROM operation_log;
-- Verify the copy
SELECT COUNT(*) FROM operation_log;
SELECT COUNT(*) FROM operation_log_copy;
-- Delete original table
DROP TABLE operation_log
-- Rename copy
RENAME TABLE operation_log_copy TO operation_log;
```
### Option 2: Delete and Recreate an Operation Log Table
This will erase all base logs. You'll lose information about past changes, but snapshots will remain unaffected.
Use this method if you have limited disk space. It immediately frees up space occupied by the table.
1. Connect to MariaDB: `docker exec -it mariadb mariadb -u root -p`
2. Execute the following commands:
```sql
USE dtable_db;
SHOW CREATE TABLE operation_log;
-- This returns the recreate statement
DROP TABLE operation_log
-- Paste the recreate statement here, adding ";" at the end
CREATE TABLE `operation_log` (...);
```
By following these steps, you can effectively manage the disk space used by the `operation_log` table in your SeaTable installation.
## Clean expired sessions
The `django_session` table is used to store user sessions. Expired sessions are not cleaned automatically, the database table will become large when you have a lot of users. The expired sessions can be cleaned up through the `clearsessions` command:
```bash
docker exec -it seatable-server /bin/bash
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py clearsessions
```
## Database Analysis Commands for SeaTable
Here's a concise guide for database analysis of a SeaTable Server.
### Determine Database Table Sizes
Use the command line tool `ncdu` on `/opt/mariadb` for an easy-to-navigate overview of table sizes. Here is an example output. Typically operation_log is by far the biggest table of all.
=== "Command"
```bash
$ cd /opt/mariadb
$ ncdu
```
=== "Result"
```sql
--- /opt/mariadb/dtable_db --------------------------
1.7 GiB [###########] operation_log.ibd
72.0 MiB [ ] django_session.ibd
60.0 MiB [ ] delete_operation_log.ibd
23.0 MiB [ ] activities.ibd
596.0 KiB [ ] dtable_external_apps.ibd
```
### Analyze Operation Log
To find bases with the most operations:
=== "Command"
```sql
SELECT dtable_uuid, COUNT(*) AS entry_count
FROM operation_log
GROUP BY dtable_uuid;
```
=== "Result"
```sql
+----------------------------------+-------------+
| dtable_uuid | entry_count |
+----------------------------------+-------------+
| 0114790c116d46fd8b9f2f9331fab623 | 2 |
| 014a4d23b28147f180f790ae8146c053 | 37 |
| 01bee901b3dc43df8df0ee58c0ab53a6 | 3312 |
| 038a126c86c14b55896ceff03237e72a | 1 |
| 04e403d181e14c41b9026d7f2d9b648b | 324 |
| 0558d382ef804d5d9eb4e682a3eaa99d | 41 |
...
```
### Identify Active Users (for a specific base)
For a specific base like `01bee901b3dc43df8df0ee58c0ab53a6`:
=== "Command"
```sql
SELECT author, COUNT(*) AS entry_count
FROM operation_log
WHERE dtable_uuid = '01bee901b3dc43df8df0ee58c0ab53a6'
GROUP BY author
ORDER BY entry_count DESC;
```
=== "Result"
```sql
+---------------------------------------------+-------------+
| author | entry_count |
+---------------------------------------------+-------------+
| | 2633 |
| 126a619d86964f78b1871a1738706225@auth.local | 267 |
| 1bd28d36f01840f7a4db2d813851b951@auth.local | 168 |
| dtable-web | 32 |
| faf94d5676414a1d887e538fda19fafd@auth.local | 28 |
```
### Analyze Change Frequency
To view changes over time:
=== "Command"
```sql
SELECT FROM_UNIXTIME(FLOOR(op_time / 3600000) * 3600) AS hour_interval,
COUNT(*) AS entry_count
FROM operation_log
WHERE dtable_uuid = '01bee901b3dc43df8df0ee58c0ab53a6'
GROUP BY hour_interval
ORDER BY hour_interval;
```
=== "Result"
```sql
+---------------------+-------------+
| hour_interval | entry_count |
+---------------------+-------------+
| 2024-09-12 13:00:00 | 7 |
| 2024-09-12 14:00:00 | 50 |
| 2024-09-12 15:00:00 | 83 |
| 2024-09-12 16:00:00 | 63 |
| 2024-09-12 17:00:00 | 53 |
```
### Remove Base Entries
To safely remove all entries for a specific base from operation_log:
=== "Command"
```sql
DELETE FROM operation_log WHERE dtable_uuid = '01bee901b3dc43df8df0ee58c0ab53a6';
```
=== "Result"
```sql
Query OK, 3312 rows affected (0.094 sec)
```
---
Source: https://admin.seatable.com/maintenance/storage-cleanup/
# Storage Cleanup (Garbage Collection)
SeaTable uses storage de-duplication technology to reduce storage usage. The underlying data blocks will not be removed immediately after you delete a file or a base. As a result, the number of unused data blocks will increase on SeaTable server.
To release the storage space occupied by unused blocks, you have to run a **garbage collection** program to clean up unused blocks on your server.
You can add [Ofelia](../installation/components/ofelia.md) to your SeaTable deployment to run the garbage collection process on a [configurable interval](../installation/components/ofelia.md#configuration).
This ensures that any unused data blocks will be automatically cleaned up.
## Configuration
Add the following lines to `seafile.conf` to keep deleted files for only 60 days:
```ini
[history]
keep_days = 60
```
The value of `keep_days` can have a significant impact on the number of objects stored on the filesystem or in S3.
A lower value of `keep_days` will allow the garbage collector to remove more objects, reducing the storage requirements as well as the number of objects.
## Dry-run mode
To see how much garbage can be collected without actually removing any garbage, use the **dry-run** option:
```bash
docker exec seatable-server /opt/seatable/scripts/seatable.sh gc --dry-run
```
The output should look like:
```text
Starting seafserv-gc, please wait ...
2021-04-27 14:30:13 gc-core.c(904): Database is MySQL/Postgre/Oracle, use online GC.
2021-04-27 14:30:13 gc-core.c(928): Using up to 1 threads to run GC.
2021-04-27 14:30:13 gc-core.c(873): GC version 1 repo plugins repo(92ba689b-51a3-457b-a264-1e46537025c8)
2021-04-27 14:30:13 gc-core.c(609): No blocks for repo 92ba689b, skip GC.
2021-04-27 14:30:13 gc-core.c(873): GC version 1 repo My Workspace(7041b9ea-cec7-43a1-9639-70aaeb572aed)
2021-04-27 14:30:13 gc-core.c(615): GC started for repo 7041b9ea. Total block number is 14.
2021-04-27 14:30:13 gc-core.c(78): GC index size is 1024 Byte for repo 7041b9ea.
2021-04-27 14:30:13 gc-core.c(390): Populating index for repo 7041b9ea.
2021-04-27 14:30:13 gc-core.c(369): Traversed 22 commits, 14 blocks for repo 7041b9ea.
2021-04-27 14:30:13 gc-core.c(682): Scanning and deleting unused blocks for repo 7041b9ea.
2021-04-27 14:30:13 gc-core.c(700): GC finished for repo 7041b9ea. 14 blocks total, about 14 reachable blocks, 0 blocks are removed.
2021-04-27 14:30:13 gc-core.c(873): GC version 1 repo My Library Template(3fe6b035-2e0f-4c2f-9347-2673b5778e72)
2021-04-27 14:30:13 gc-core.c(609): No blocks for repo 3fe6b035, skip GC.
...
2021-04-27 14:30:13 gc-core.c(773): === Repos deleted by users ===
2021-04-27 14:30:13 gc-core.c(1041): Repo fb882070-d158-4433-a038-6be0117560e0 can be GC'ed.
...
2021-04-27 14:30:13 gc-core.c(980): === GC is finished ===
2021-04-27 14:30:13 gc-core.c(1226): The following repos have blocks to be removed:
2021-04-27 14:30:13 gc-core.c(1229): 09a91b76-df37-44d4-81e0-416e4397c9f6
seafserv-gc run done
Done.
```
## Removing Garbage
Run a garbage collection program without adding --dry-run option to actually remove garbage block.
```bash
docker exec seatable-server /opt/seatable/scripts/seatable.sh gc
```
### Removing FS Objects
SeaTable uses Seafile to store assets that have been uploaded to bases. Internally, Seafile uses a [data model](https://manual.seafile.com/13.0/develop/data_model/) similar to Git, which consists of `commit`, `fs` and `block` objects.
By default, `seatable.sh gc` will only remove garbage or unreferenced `block` objects. Objects of type `fs` (filesystem) won't be removed.
You can add the `--rm-fs` commandline option to also remove garbaged or unreferenced `fs` objects:
```bash
docker exec seatable-server /opt/seatable/scripts/seatable.sh gc --rm-fs
```
If you use the included [Ofelia](../installation/components/ofelia.md) configuration to run the GC process, the `--rm-fs` flag is added by default.
---
Source: https://admin.seatable.com/maintenance/big-data-cleanup/
# Big Data Cleanup
Unused or deleted big data storage is not automatically reclaimed. To free up disk space for bases that use large amounts of big data storage, run the following commands as needed.
## Detecting Bases with Large Big Data Storage
Check the size of the folders stored in `/opt/seatable-server/seatable/db-data`.
Using the `ncdu` tool is recommended, as it shows the storage usage per folder.
Example output:
```text
--- /opt/dtable-db/seatable/db-data ------------------------------------------
135.4 MiB [##########################] /9ba24950-cd00-42dc-b5e9-233f3de2c2b6
54.0 MiB [########## ] /281b15c1-2a12-4da3-814d-145cb703a55b
40.5 MiB [####### ] /76a4c7e8-2422-4c3f-9282-40e1e9fd5afc
33.3 MiB [###### ] /35a51052-0f29-4628-91f3-9aad177e1bd2
33.1 MiB [###### ] /52fd3b11-d00f-4fdf-b2ce-d306e08c4697
30.4 MiB [##### ] /9220dada-2a6a-4392-8dee-0d77af0f5a02
28.9 MiB [##### ] /3adc3d74-1783-40a9-9d05-245e9dc03f21
```
Each folder name corresponds to the UUID of a base.
## Garbage Collection for Big Data
Run garbage collection on a base to remove unused or deleted big data entries:
```bash
docker exec -it seatable-server bash
cd /opt/seatable/seatable-server-latest/
./dtable-db-admin.sh gc ""
```
Replace `` with the actual UUID of the base.
This command reclaims unreferenced data blocks and cleans up invalid references in the big data store.
## Flatten Command
After running garbage collection, you may see log warnings such as:
```text
Unable to read: Key: xxx, file with ID not found
```
These messages can appear during backup operations. To clean up remaining invalid keys, run the flatten command:
```bash
./dtable-db-admin.sh flatten ""
```
The warning occurs when garbage collection removes value files but leaves behind invalid key entries.
This does not affect data integrity and is primarily an internal maintenance issue.
---
Source: https://admin.seatable.com/maintenance/filesystem-check/
# File System Check
On the server side, SeaTable stores the files in the libraries in an internal format. SeaTable has its own representation of directories and files (similar to Git).
With default installation, these internal objects are stored in the server's file system directly (such as Ext4, NTFS). But most file systems don't assure the integrity of file contents after a hard shutdown or system crash. So if new SeaTable internal objects are being written when the system crashes, they can be corrupt after the system reboots. This will make part of the corresponding library not accessible.
Note: If you store the seafile-data directory in a battery-backed NAS (like EMC or NetApp), or use S3 backend available in the Pro edition, the internal objects won't be corrupt.
SeaTable server comes with a seaf-fsck tool to help you recover from this corruption (similar to git-fsck tool). This tool recovers any corrupted library back to its last consistent and usable state.
We provide a seaf-fsck.sh script. The seaf-fsck tool accepts the following arguments:
```bash
docker exec -it seatable-server /opt/seatable/seatable-server-latest/seaf-fsck.sh [--repair|-r] [--export|-E export_path] [repo_id_1 [repo_id_2 ...]]
```
There are three modes of operation for seaf-fsck:
1. checking integrity of tables.
2. repairing corrupted tables.
3. exporting tables.
You can add [Ofelia](../installation/components/ofelia.md) to your SeaTable deployment to run the `seaf-fsck` tool on a [configurable interval](../installation/components/ofelia.md#configuration).
This will regularly verify the integrity of all Seafile libraries.
## Checking Integrity of Libraries
Running seaf-fsck.sh without any arguments will run a **read-only** integrity check for all tables.
```bash
docker exec -it seatable-server /opt/seatable/seatable-server-latest/seaf-fsck.sh
```
If you want to check integrity for specific tables, just append the library id's as arguments:
```bash
cd seafile-server-latest
./seaf-fsck.sh [library-id1] [library-id2] ...
```
The output looks like:
```text
[02/13/15 16:21:07] fsck.c(470): Running fsck for repo ca1a860d-e1c1-4a52-8123-0bf9def8697f.
[02/13/15 16:21:07] fsck.c(413): Checking file system integrity of repo fsck(ca1a860d)...
[02/13/15 16:21:07] fsck.c(35): Dir 9c09d937397b51e1283d68ee7590cd9ce01fe4c9 is missing.
[02/13/15 16:21:07] fsck.c(200): Dir /bf/pk/(9c09d937) is corrupted.
[02/13/15 16:21:07] fsck.c(105): Block 36e3dd8757edeb97758b3b4d8530a4a8a045d3cb is corrupted.
[02/13/15 16:21:07] fsck.c(178): File /bf/02.1.md(ef37e350) is corrupted.
[02/13/15 16:21:07] fsck.c(85): Block 650fb22495b0b199cff0f1e1ebf036e548fcb95a is missing.
[02/13/15 16:21:07] fsck.c(178): File /01.2.md(4a73621f) is corrupted.
[02/13/15 16:21:07] fsck.c(514): Fsck finished for repo ca1a860d.
```
The corrupted files and directories are reported.
Sometimes you can see output like the following:
```text
[02/13/15 16:36:11] Commit 6259251e2b0dd9a8e99925ae6199cbf4c134ec10 is missing
[02/13/15 16:36:11] fsck.c(476): Repo ca1a860d HEAD commit is corrupted, need to restore to an old version.
[02/13/15 16:36:11] fsck.c(314): Scanning available commits...
[02/13/15 16:36:11] fsck.c(376): Find available commit 1b26b13c(created at 2015-02-13 16:10:21) for repo ca1a860d.
```
This means the "head commit" (current state of the library) recorded in database is not consistent with the library data. In such case, fsck will try to find the last consistent state and check the integrity in that state.
Tips: **If you have many libraries, it's helpful to save the fsck output into a log file for later analysis.**
## Repairing Corruption
Corruption repair in seaf-fsck basically works in two steps:
1. If the library state (commit) recorded in database is not found in data directory, find the last available state from data directory.
2. Check data integrity in that specific state. If files or directories are corrupted, set them to empty files or empty directories. The corrupted paths will be reported, so that the user can recover them from somewhere else.
Running the following command repairs all the libraries:
```bash
cd seafile-server-latest
./seaf-fsck.sh --repair
```
Most of time you run the read-only integrity check first, to find out which libraries are corrupted. And then you repair specific libraries with the following command:
```bash
cd seafile-server-latest
./seaf-fsck.sh --repair [library-id1] [library-id2] ...
```
After repairing, in the library history, seaf-fsck includes the list of files and folders that are corrupted. So it's much easier to locate corrupted paths.
### Best Practice for Repairing a Library
To check all libraries and find out which library is corrupted, the system admin can run seaf-fsck.sh without any argument and save the output to a log file. Search for keyword "Fail" in the log file to locate corrupted libraries. You can run seaf-fsck to check all libraries when your Seafile server is running. It won't damage or change any files.
When the system admin find a library is corrupted, he/she should run seaf-fsck.sh with "--repair" for the library. After the command fixes the library, the admin should inform user to recover files from other places. There are two ways:
- Upload corrupted files or folders via the web interface
- If the library was synced to some desktop computer, and that computer has a correct version of the corrupted file, re-syncing the library on that computer will upload the corrupted files to the server.
## Exporting Libraries to File System
Since version 4.2.0, you can use seaf-fsck to export all the files in libraries to external file system (such as Ext4). This procedure doesn't rely on the seafile database. As long as you have your seafile-data directory, you can always export your files from Seafile to external file system.
The command syntax is
```bash
cd seafile-server-latest
./seaf-fsck.sh --export top_export_path [library-id1] [library-id2] ...
```
The argument `top_export_path` is a directory to place the exported files. Each library will be exported as a sub-directory of the export path. If you don't specify library ids, all libraries will be exported.
Currently only un-encrypted libraries can be exported. Encrypted libraries will be skipped.
---
Source: https://admin.seatable.com/maintenance/domain-change/
# Changing Domain (URL)
When changing the domain of your SeaTable Server, you must not only update configuration files but also ensure that all internal file and image URLs inside bases are updated. This section describes all necessary steps.
This command does not update all URLs within a base. The following will remain broken after execution:
- Embedded images in TLDRAW drawings will no longer display (files exist, but links are outdated).
- Existing Page Design plugin templates cannot be opened.
For assistance, contact us at support@seatable.com.
## 1. Update Configuration
If your SeaTable Server’s URL changes (for example, from `https://old.example.com` to `https://new.example.com`), start by updating the following files:
- **`/opt/seatable-compose/.env`** – Replace all instances of the old domain with the new one, especially `SEATABLE_SERVER_HOSTNAME`.
- **`/opt/seatable-server/seatable/dtable_web_settings.py`** – Update variables containing the old domain, such as `DTABLE_WEB_SERVICE_URL`, `FILE_SERVER_ROOT` or any related configuration keys.
After saving the changes, [restart all containers](./restart-seatable.md) to apply the new configuration.
## 2. Update SSL Certificates
If you are using custom TLS/SSL certificates (not managed by Let’s Encrypt), you must [replace your existing certificate](../installation/advanced/custom-certificates.md) and key files to match the new domain. Make sure your new certificate is valid for the new domain before restarting the SeaTable services.
## 3. Transfer URLs Inside Bases
Changing the domain causes images or files stored in bases to become unreadable. To fix existing links to these assets in file/image columns, SeaTable provides a management command that replaces all image and file URLs from the old domain with the new one.
Open a shell inside the SeaTable container:
```bash
docker exec -it seatable-server bash
cd /opt/seatable/seatable-server-latest/dtable-web
```
Run one of the following commands:
??? success "For all bases"
```bash
seatable.sh python-env ./manage.py domain_transfer -all -od -nd
```
To change the domain from `https://old.example.com` to `https://new.example.com`, run:
```bash
seatable.sh python-env ./manage.py domain_transfer -all -od https://old.example.com -nd https://new.example.com
```
??? success "For a single base"
```bash
seatable.sh python-env ./manage.py domain_transfer -uuid <:base uuid> -od -nd
```
To change the domain for a base with UUID `695fa115-4927-4be1-b5b6-fbbbabd43b72` from `https://old.example.com` to `https://new.example.com`, run:
```bash
seatable.sh python-env ./manage.py domain_transfer -uuid 695fa115-4927-4be1-b5b6-fbbbabd43b72 -od https://old.example.com -nd https://new.example.com
```
---
Source: https://admin.seatable.com/maintenance/base-export/
# Exporting a Base from the Command Line
SeaTable provides two ways to export a base using the command line. You can perform a simple export to a single `.dtable` file or an advanced export that includes all data, including big data content. Both methods bypass the limits of the web interface.
## Simple Export: Create a .dtable File
The simple export generates a ready-to-use `.dtable` file that can be imported into another SeaTable instance.
### Advantages
- Easy to run and import
- Produces a single `.dtable` file
### Limitations
- Maximum export size: 100 MB
- Does not include big data content from the SeaTable Big Data backend
### Export command
Use the following command to export a base by its `base_uuid`. The `.dtable` file will be saved to your current directory. In this example, the `/shared` folder is used because it is accessible from the SeaTable host.
```bash
docker exec -it seatable-server bash
cd /shared
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py export_dtable
```
Replace `` with your actual base UUID.
### Excluding Attached Files and Images
To export only the structured base data and omit all assets (images, files), use the `--ignore-asset` option:
```bash
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py export_dtable --ignore-asset true
```
### If the Export Fails Due to Size Limits
If your base contains many attached files/images, you might encounter the `max_download_dir_size` limitation. You can increase this limit (default is 100 MB) in `seafile.conf`:
```ini
[fileserver]
max_download_dir_size=1000
```
Then [restart SeaTable](../maintenance/restart-seatable.md)
This setting determines the maximum export size for `.dtable` files. For example, with `max_download_dir_size=1000`, exports up to 1 GB are allowed. You can set this value to any size you require.
## Advanced Export: Export to a Folder with All Data
The advanced export uses the `export_dtable_folder` command. It creates a local folder that contains all base data, assets, and big data content. This approach is ideal for complete backups or when moving large datasets.
### Advantages
- Includes data from the Big Data backend
- No size limitation (overcomes the 100 MB default limit)
### Limitations
- The export produces a folder structure, not a single `.dtable` file
- Requires manual handling when re-importing or transferring
### Export Command
Run the following command to export all content, including big data, to your current folder. In this example, the `/shared` folder is used because it is accessible from the SeaTable host.
```bash
docker exec -it seatable-server bash
cd /shared
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py export_dtable_folder
```
This command creates:
- a folder with the name of the base
- inside this folder:
- a content.json file with the base’s structure and data
- one or more subfolders for assets and big data files
### Optional parameters
- `--ignore-archive-backup true`: Skips the export of archived backup data. Use this if archived backups are not required in the exported result.
## Importing an Advanced Export
To import an exported base folder into another group/workspace, use the following command. The import takes typically much longer than the export.
```bash
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py import_dtable_folder --workspace-id="" --path=""
```
Replace `` with the ID of the target workspace/group and provide the path to the folder containing the export.
Open any base in the target workspace (group or "My Bases") via the web interface.
Extract the numeric ID from the URL. For example, in `https://cloud.seatable.io/workspace/156522/dtable/Customers/`, the workspace ID is `156522`.
**Important**: The workspace ID is not the group id.
After running the command, check that the output indicates a successful import.
### Known Issues in Version 6.0
In SeaTable version 6.0, the import function has a known bug that prevents bases from being created correctly in the database, leaving the `name` field empty.
This disrupts the web interface for all users with access to the affected workspace.
**Fix**: Manually set a name in the `dtable_db.dtables` table. This resolves the issue immediately.
SeaTable exports bases with spaces/special chars (e.g., "CRM and Sales" → `/share/CRM and Sales`), which `import_dtable_folder` rejects.
Rename folders to use only letters, numbers, underscores, or hyphens (e.g., `CRM_and_Sales` or `CRM-Sales`) before importing.
---
Source: https://admin.seatable.com/maintenance/repair-base/
# Repair/Prune a base
SeaTable provides a repair function that fixes typical structural problems with a base and prunes unused data.
## What does it do?
The repair function performs the following operations:
- **Ensures structural integrity**: every table must have a column with the ID `0000` (the first column)
- **Removes orphaned data**: rows and views without a valid ID are deleted
- **Prunes deleted columns**: removes the _values_ of deleted columns from the JSON object
The pruning step can free up significant space. When you delete a column in SeaTable, only the _column definition_ is removed immediately — the actual _column values_ remain in the JSON object. Over time, this can cause the base to approach the 200MB size limit. The repair function cleans up this leftover data.
## When to use it
- A base is approaching the 200MB size limit
- A base shows unexpected behavior (missing first column, phantom rows)
- After deleting many columns with large datasets
- As a maintenance step for long-lived bases with frequent schema changes
## Usage
There are two ways to trigger the repair function.
### Option 1: System Admin Web UI
System administrators can repair a base directly from the web interface:
1. Log in as system administrator
2. Navigate to the **System Admin** area
3. Open **Bases** and find the affected base
4. Click the **three-dot menu** of the base and select **Repair**
### Option 2: Command line
For the command line execution you need the `base_uuid`, which you can find in the URL when opening the base in the browser.
```bash
docker exec -it seatable-server bash
cd /templates
seatable.sh python-env /opt/seatable/seatable-server-latest/dtable-web/manage.py repair_base
```
The repair function can be executed while SeaTable is running. Users may experience a brief interruption for the affected base while the repair is in progress.
---
Source: https://admin.seatable.com/maintenance/password-reset/
# Password Reset
#### User Management
When you set up SeaTable, you should have set up an admin account. After you log in as an admin, you may add/delete users.
#### Resetting User Password
Administrator can reset password for a user in "System Admin" page.
In a private server, the default settings doesn't support users to reset their password by email. If you want to enable this, you have first to [set up notification email](../configuration/sending-email.md).
#### Forgot Admin Account or Password?
You may create a new admin account from the command line. Use these commands and follow the instructions on the screen.
```bash
docker exec -it seatable-server bash
seatable.sh superuser
```
After logging in the new admin account, you can reset the original admin account's password.
---
Source: https://admin.seatable.com/maintenance/logs/
# Logs
## Log files of SeaTable server
The SeaTable logs are under `/shared/seatable/logs` in the docker, or `/Your SeaTable data volume/seatable/logs` in the server that runs the docker.
Main log files:
- dtable_web.log: logs for dtable-web
- dtable-events.log: logs for dtable-events
- dtable_events_io.log: logs for Base's import or export and Excel or CSV file import or export
- dtable_events_message.log: logs for sending emails in the dtable-events background
- dtable-server.log: logs for dtable-server
- dtable-db.log: logs for dtable-db
- dtable-db-error.log: error logs for dtable-db
- dtable-db-access.log: query log for dtable-db
- dtable-db-slow.log: slow query log for dtable-db
Other log files:
- seafile.log: logs of Seafile server
- slow_logs: Slow request logs, which can be used to debug performance issues
- monitor.log: Monitor logs, monitor.sh can auto restart the unexpectedly closed server
- init.log: Logs for docker initialization script
## Log files of Nginx server
The Nginx logs are under `/shared/nginx-logs`, or `/Your SeaTable data volume/nginx-logs` in the server that runs the docker.
- dtable-web.access.log
- dtable-web.error.log
- access.log
- error.log
## Logrotate
SeaTable's Docker container executes nightly log rotation cron jobs for both SeaTable and nginx logs. The cron jobs are configured as follows:
```text
54 23 * * * /usr/sbin/logrotate -vf /templates/logrotate-conf/seatable-nginx 2>> /opt/seatable/logs/logrotate.log
55 23 * * * /usr/sbin/logrotate -vf /templates/logrotate-conf/seatable 2>> /opt/seatable/logs/logrotate.log
```
### Logrotate Configuration
The log rotation configuration is straightforward and includes the following parameters:
```json
{
daily
missingok
rotate 7
# compress
# delaycompress
dateext
dateformat .%Y-%m-%d
notifempty
create 644 root root
sharedscripts
postrotate
if [ -f /opt/seatable/pids/seafile.pid ]; then
kill -USR1 `cat /opt/seatable/pids/seafile.pid`
fi
if [ -f /opt/seatable/pids/dtable-db.pid ]; then
kill -USR1 `cat /opt/seatable/pids/dtable-db.pid`
fi
if [ -f /opt/seatable/pids/dtable-storage-server.pid ]; then
kill -USR1 `cat /opt/seatable/pids/dtable-storage-server.pid`
fi
if [ -f /opt/seatable/pids/api-gateway.pid ]; then
kill -USR1 `cat /opt/seatable/pids/api-gateway.pid`
fi
if [ -f /opt/seatable/pids/dtable-web.pid ]; then
pkill -HUP gunicorn
fi
find /opt/seatable/logs/ -mtime +7 -name "*.log*" -exec rm -f {} \;
endscript
}
```
This configuration ensures:
- Daily log rotation.
- Retention of logs for seven days.
- Addition of timestamps to rotated logs using dateext.
- Automatic removal of old logs older than seven days.
All relevant configuration files are located in `/templates/logrotate-conf` within the SeaTable Docker container.
### Customizing Logrotate Configuration
To modify the log rotation settings, you can mount a custom configuration file using Docker Compose.
In order to ensure that this modification is preserved across version upgrades, you should **not** modify the default `.yml` files that we distribute as part of the installation process.
Please read our guide on how to [customize the configuration](../configuration/customizations.md) of your SeaTable instance before proceeding.
In order to customize the configuration file used by `logrotate`, you can specify a volume mount definition inside a `custom-seatable-server.yml` file:
```yaml
services:
seatable-server:
volumes:
- ./logrotate-seatable-custom.conf:/templates/logrotate-conf/seatable:ro
```
Do not forget to add this file to the `COMPOSE_FILE` variable inside your `.env` file.
---
Source: https://admin.seatable.com/maintenance/debugging/
# Advanced debugging by adding error messages
Sometimes SeaTable does not behave like you expect it to behave. Then it is time for some advanced debugging skills. This article debugs a possible problem to give you some knowledge that might help you to solve other problems, too. To follow this explanation you should have at least some development experience.
## The problem: User not found
Imagine the situation that the "Share a base with other users" does not show the users you expected.

You have no idea why the auto complete function is not working as expected. So let's find out.
## Check the Developer Tools of your browser
The first check that you can perform is the Browser Console and the networking tab of your developer tools.
### The console tab
In this case there are not errors in the console tab. That means there are not general JavaScript execution errors or bad Api endpoints. If you have problems inside your network like firewalls blocking traffic, unsigned certificates or something like that, you will most likely see an error in the browser console tab. In this case there is no error message.
### The network tab
In the network tab, you can detect what kind of calls are executed, if you search for a user.

From the results you can see that with every key stroke SeaTable executes a command like:
```bash
/api2/search-user/?q=demo
```
So let's find this source code in the SeaTable Container.
## Find the Python Source Code
Access your SeaTable Server container and let's search for the source code. I start my search in `dtable-web/seahub`.
```bash
docker exec -it seatable-server bash
cd /opt/seatable/seatable-server-latest/dtable-web/seahub
grep -R "search-user" ./
# the result
./api2/urls.py: re_path(r'^search-user/$', SearchUser.as_view(), name='search-user'),
```
Now let's get a closer look at this `/api2/urls.py` at `/opt/seatable/seatable-server-latest/dtable-web/seahub/api2/urls.py`.
There you can find at the beginning of this file, this content:
```bash
from .endpoints.search_user import SearchUser
```
This tells us, that the source code of this search function is in the file `/opt/seatable/seatable-server-latest/dtable-web/seahub/api2/endpoints/search_user.py`.
## Add custom error messages
In this python file, I can immediately see that there is the `class SearchUser(APIView)`. In the class I can see that the code checks for some parameters like:
- user.permission.can_use_global_address_book
- CLOUD_MODE
- is_org_context
Also I can see that SeaTable first generates a list of potential users and then removes out unwanted entries. So why not check if the user we are looking for is in the full list and then removed or if the user is not in there.
Let's add this additional logging at line 94. Make sure that you use the right indentation, because otherwise the python code will throw errors.
```bash
## search finished, now filter out some users
logger.error("This is email_list: %s " % email_list)
```
## Check the logs
Now let's restart SeaTable and check the dtable_web.log for more details.
```bash
# we are still in the SeaTable Server container.
seatable.sh restart
tail -f /opt/seatable/logs/dtable_web.log
```
---
Source: https://admin.seatable.com/maintenance/secrets/
# Secrets Management
## SECRET_KEY
During initialization, SeaTable generates a `SECRET_KEY` and saves this random string to the configuration file `dtable_web_settings.py`.
This `SECRET_KEY` serves two critical functions:
1. Generating user sessions
2. Encrypting "thirdparty account passwords"
It is strongly discouraged to change the `SECRET_KEY` after initial setup. Modifying it will result in:
- "Thirdparty accounts" becoming inaccessible
- All current user sessions becoming invalid
If you absolutely must change the `SECRET_KEY`, follow these steps:
1. Delete all thirdparty accounts from all bases
2. Stop SeaTable
3. Change the `SECRET_KEY`
4. Restart SeaTable
5. All users will need to log in again
6. Create new thirdparty accounts as needed
## PRIVATE_KEY
**Starting with v5.3**, this secret should be provided via environment variable `JWT_PRIVATE_KEY` in your `/opt/seatable-compose/.env` file. There is no need to keep the two variables in your configuration files.
??? warning "Configured in configuration files before 5.3"
SeaTable generates a `PRIVATE_KEY` during initialization for secure inter-component communication between dtable-web and dtable-server/dtable-db. This key is used in two configuration files and must be identical:
1. `dtable_server_config.json`: as `private_key`
2. `dtable_web_settings.py`: as `DTABLE_PRIVATE_KEY`
If you update this `PRIVATE_KEY`, always ensure that these PRIVATE_KEY values match across both configuration files to maintain proper system functionality.
---
Source: https://admin.seatable.com/maintenance/mariadb-tuning/
# MariaDB Performance Tuning
SeaTable's default MariaDB configuration works well for small installations. For larger deployments or when you notice slow database queries, tuning MariaDB can significantly improve performance.
If you prefer automated optimization, consider using [Releem](../installation/components/releem.md). It monitors your database workload and recommends optimized settings.
## Key settings
The most impactful setting is `innodb_buffer_pool_size` — the memory area where InnoDB caches table data and indexes. As a rule of thumb, set it to **50–70% of your server's available RAM** after accounting for SeaTable and other services.
| Setting | Default | Recommendation | Purpose |
| ------------------------- | ------- | ----------------------- | ----------------------------------------- |
| `innodb_buffer_pool_size` | 128M | 50–70% of available RAM | Cache for table data and indexes |
| `innodb_log_file_size` | 48M | 256M | Redo log size, improves write performance |
| `max_connections` | 151 | 200–300 | Max concurrent database connections |
## Apply custom settings
### 1. Create a configuration file
Create `/opt/seatable-compose/99-mariadb-custom.cnf` with your tuned values. Adjust `innodb_buffer_pool_size` to match your server's RAM:
```ini
[mariadb]
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
max_connections = 200
```
### 2. Mount the configuration file
Since the default definition of the `mariadb` service inside `seatable-server.yml` [should not be modified](../configuration/customizations.md), you should instead create a file named `custom-mariadb.yml` in `/opt/seatable-compose/` that only contains the configuration override:
```yaml
services:
mariadb:
volumes:
- ./99-mariadb-custom.cnf:/etc/mysql/conf.d/99-mariadb-custom.cnf
```
Add `custom-mariadb.yml` to the `COMPOSE_FILE` variable in your `.env` file. This ensures that `seatable-server.yml` and `custom-mariadb.yml` are [merged together](../configuration/customizations.md).
### 3. Restart MariaDB
```bash
cd /opt/seatable-compose
docker compose up -d mariadb
```
### 4. Verify the settings
Confirm that your settings were applied:
```bash
docker exec -it mariadb mariadb -uroot -p${MARIADB_PASSWORD} -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
```
## Sizing examples
| Server RAM | Other services | Recommended `innodb_buffer_pool_size` |
| ---------- | ------------------------------ | ------------------------------------- |
| 8 GB | SeaTable only | 2–4G |
| 16 GB | SeaTable + Python Pipeline | 6–8G |
| 32 GB | SeaTable + multiple components | 12–16G |
---
Source: https://admin.seatable.com/maintenance/helper-scripts/
# Helper Scripts
After installing SeaTable, `/opt/seatable-compose/tools` contains the following shell scripts in order to make administrative operations more convenient.
## User management
### activate-user.sh
This script allows you to enable an **existing** SeaTable user inside the database.
Simply provide the user's contact email address as a parameter:
=== "Input"
```bash
./tools/activate-user.sh "user@email.com"
```
=== "Output"
```text
--------------
UPDATE ccnet_db.EmailUser SET is_active = 1 WHERE email = (SELECT user FROM dtable_db.profile_profile WHERE contact_email = 'user@email.com')
--------------
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Bye
Success: Activated user user@email.com
```
### deactivate-user.sh
This script allows you to disable an existing SeaTable user inside the database.
Simply provide the user's email address as a parameter:
=== "Input"
```bash
./tools/deactivate-user.sh "user@email.com"
```
=== "Output"
```text
--------------
UPDATE ccnet_db.EmailUser SET is_active = 0 WHERE email = (SELECT user FROM dtable_db.profile_profile WHERE contact_email = 'user@email.com')
--------------
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
Bye
Success: Deactivated user user@email.com
```
### user-stats.sh
This script will print your current license limit and query the database for the number of enabled users:
=== "Input"
```bash
./tools/user-stats.sh
```
=== "Output"
```text
User limit according to license file: 3
Users in database:
+-------+--------------+
| users | active_users |
+-------+--------------+
| 2 | 2 |
+-------+--------------+
```
## Database management
### db-shell.sh
This script will give you an interactive shell inside the MariaDB container. You can use this to directly run SQL commands.
=== "Input"
```bash
./tools/db-shell.sh
```
=== "Output"
```text
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 73
Server version: 11.4.3-MariaDB-ubu2404 mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
```
### dump-database.sh
This script will dump all three databases (`ccnet_db`, `dtable_db` and `seahub_db`) to `/opt/seatable-backup` on the host.
=== "Input"
```bash
./tools/dump-database.sh
```
=== "Output"
```text
Success: Dumped databases into /opt/seatable-backup
```
=== "Created Files"
```text
total 228
-rw-r--r-- 1 root root 12184 May 23 11:30 ccnet_db-2025-05-23-11-30-27.sql
-rw-r--r-- 1 root root 177499 May 23 11:30 dtable_db-2025-05-23-11-30-27.sql
-rw-r--r-- 1 root root 38402 May 23 11:30 seafile_db-2025-05-23-11-30-27.sql
```
## Troubleshooting
### check-dtable-web.sh
This script allows you to check the status of `dtable-web`.
This is helpful in case `dtable-web` does not start up since any fatal configuration errors are currently not logged to `dtable_web.log` or the container's stdout stream.
=== "Input"
```bash
./tools/check-dtable-web.sh
```
=== "Output"
```text
System check identified no issues (0 silenced).
```
---