Distributed Databases & AI Agent Engineering Practice
Deploying the OceanBase Database in an Ubuntu Virtual Machine
Posted onInHands-on PracticeViews: Word count in article: 4.6kReading time ≈17 mins.
This article shares the complete process of deploying a standalone OceanBase Community Edition database via OBD's GUI in a WSL Ubuntu 22.04 virtual machine on a Windows laptop. It covers environment preparation, how to install RPM packages under Ubuntu, cluster and component configuration, the principles behind ob_configserver, and the OB Dashboard operations experience.
0. A Writing Contest with Prizes
The OceanBase community is organizing a writing contest with prizes on the theme of “Getting Hands-On with OBD Standalone Deployment.” For details on how to participate, see: https://ask.oceanbase.com/t/topic/35630223.
This article mainly shares the process of deploying a standalone OB Community Edition on the Linux subsystem Ubuntu on a Windows laptop, along with an explanation of the related principles.
This deployment did not include OCP; the OB cluster deployment relies on the obd web platform. After deployment, OB-Dashboard (the process is obshell, HTTP port 2886) starts automatically. Through OB-Dashboard, you can also perform some simple single-node OB operations.
2. Environment Preparation
The deployment environment is a WSL subsystem on a Windows laptop, with Ubuntu-22.04 selected. It has roughly 16 cores, 22 GB of memory, and 1 TB of space.
1 2 3
d:\Download>wsl -l -v NAME STATE VERSION * Ubuntu-22.04 Running 2
2.1 Resource Check
The official documentation states that the minimum resource specification for running OB Community Edition is 2 cores and 4 GB. Considering OB’s multi-tenancy capability, we won’t test such a small specification here; for personal production deployments, the minimum requirement is 8 cores and 16 GB.
After entering the Ubuntu system, verify the machine’s resources.
Check the number of CPUs and instruction-set options
mq@OBPILOT:~/obce/ob-deploy$ ping github.com PING github.com (20.205.243.166) 56(84) bytes of data. 64 bytes from 20.205.243.166: icmp_seq=3 ttl=110 time=85.0 ms 64 bytes from 20.205.243.166 (20.205.243.166): icmp_seq=4 ttl=110 time=84.5 ms 64 bytes from 20.205.243.166: icmp_seq=5 ttl=110 time=84.0 ms 64 bytes from 20.205.243.166 (20.205.243.166): icmp_seq=6 ttl=110 time=86.2 ms 64 bytes from 20.205.243.166: icmp_seq=7 ttl=110 time=87.1 ms 64 bytes from 20.205.243.166 (20.205.243.166): icmp_seq=8 ttl=110 time=89.3 ms ^C64 bytes from 20.205.243.166: icmp_seq=9 ttl=110 time=88.5 ms
mq@OBPILOT:~/obce/ob-deploy$ gcc --version gcc (Ubuntu 11.4.0-1ubuntu1~22.04.2) 11.4.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the sourcefor copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Check the firewall status
1 2
mq@OBPILOT:~/obce/ob-deploy$ sudo ufw status Status: inactive
The OB software is later downloaded automatically by the deployment tool.
CentOS/RHEL/Fedora and others use the RPM package management system (.rpm files), while Ubuntu/Debian and others use the Debian package management system (.deb files). These two formats are not compatible with each other, and Ubuntu’s dpkg and apt cannot directly install or manage RPM files.
The OBD software package on the official site is only available in RPM format, supporting x86 and ARM versions respectively. So there are several ways to use the RPM package under Ubuntu.
Install the rpm command.
Convert the rpm file to a deb file.
Extract the RPM package contents and install manually.
Let’s first demonstrate option 3, which helps you understand how the rpm package works.
First, install the software needed to extract the RPM package.
1 2
sudo apt update sudo apt install rpm2cpio cpio
Then create the directory ob-deploy and extract the files into it.
1 2 3
mkdir ob-deploy cd ob-deploy rpm2cpio ../ob-deploy-3.6.0-3.el7.x86_64.rpm | cpio -idmv
Looking at the extracted directory structure, you can also tell where the original RPM package would copy files to upon installation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
mq@OBPILOT:~/obce/ob-deploy$ tree -L 3 . ├── etc │ └── profile.d │ └── obd.sh └── usr ├── bin │ └── obd └── obd ├── config_parser ├── example ├── lib ├── mirror ├── optimize ├── plugins ├── web └── workflows
13 directories, 2 files
So, manually copy these directory files to the system directories.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
sudocp -r etc/* /etc/ sudocp -r usr/* /usr/ which obd
obd --version
mq@OBPILOT:~/obce/ob-deploy$ which obd /usr/bin/obd mq@OBPILOT:~/obce/ob-deploy$ obd --version OceanBase Deploy: 3.6.0 REVISION: b36013bb09a84516e56db51dba78a9d9096735e7 BUILD_BRANCH: HEAD BUILD_TIME: Sep 04 2025 10:50:58 Copyright (C) 2025 OceanBase License Apache 2.0: Apache version 2 or later <https://www.apache.org/licenses/LICENSE-2.0>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
3. Installation and Deployment
3.1 Pre-Deployment Setup
Disable the firewall (if it was enabled earlier)
1 2
mq@OBPILOT:~/obce/ob-deploy$ sudo ufw disable Firewall stopped and disabled on system startup
Ubuntu does not have an admin user by default, but it may have an admin user group, which has sudo privileges by default. This also fits OB operational needs: the admin user has sudo privileges, reducing the number of switches to root and lowering the risk of accidental operations. Security policies vary across customer companies, so this may differ from case to case.
System information as of Mon Sep 8 17:09:42 CST 2025
System load: 0.19 Processes: 55 Usage of /: 4.5% of 1006.85GB Users logged in: 1 Memory usage: 3% IPv4 address for eth0: x.x.x.x Swap usage: 0%
* Strictly confined Kubernetes makes edge and IoT secure. Learn how MicroK8s just raised the bar for easy, resilient and secure K8s cluster deployment.
mq@OBPILOT:~$ sudo service ssh status ● ssh.service - OpenBSD Secure Shell server Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2025-09-08 17:14:11 CST; 2min 52s ago Docs: man:sshd(8) man:sshd_config(5) Main PID: 4696 (sshd) Tasks: 1 (limit: 28835) Memory: 1.7M CGroup: /system.slice/ssh.service └─4696 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
Sep 08 17:14:11 OBPILOT systemd[1]: Starting OpenBSD Secure Shell server... Sep 08 17:14:11 OBPILOT sshd[4696]: Server listening on 0.0.0.0 port 22. Sep 08 17:14:11 OBPILOT sshd[4696]: Server listening on :: port 22. Sep 08 17:14:11 OBPILOT systemd[1]: Started OpenBSD Secure Shell server.
Prepare the data directories
OB usually has two main directories. The data directory goes in /data/1, and the (transaction) log directory goes in /data/log1. In a production environment, these two directories should use independent disks and file systems. This is a test environment, so they share a single disk and file system.
Here we deploy under the current user (the regular user mq); personally, I think deploying under root is very dangerous.
1 2 3
mq@OBPILOT:~$ sudo obd web start start OBD WEB in 0.0.0.0:8680 please open http://127.0.1.1:8680
Note that I started it with the sudo command. Using it or not makes a big difference: without it, the installation goes under the current user; with it, you can install under different users (and I didn’t want to install under the root user).
The access address shown here is 127.0.0.1. Since this is a virtual machine, the outside world certainly cannot access this address, so we also need to find the VM’s address.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
mq@OBPILOT:~$ ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet 10.255.255.254/32 brd 10.255.255.254 scope global lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:15:5d:73:e0:00 brd ff:ff:ff:ff:ff:ff inet x.x.x.x/20 brd x.x.x.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::215:5dff:fe73:e000/64 scope link valid_lft forever preferred_lft forever
Seeing this page means you’re a quarter of the way there. Click “Start the Experience Journey.”
Here OBD WEB provides OB deployment, OB Cloud Platform deployment, and component management. This article mainly explores standalone OB deployment, so we won’t choose [OB Cloud Platform]; we’ll choose the first option, [OB and Supporting Tools].
Afterward, you’ll enter the OB deployment wizard page.
3.2.1 Deployment Configuration
Set the cluster name and select the database version
The cluster name is very important and cannot be changed later.
For version selection, if it’s for formal business use, check the Release Notes on the official site. Generally, prefer an LTS version (4.2.5 or 4.3.5), and within it choose the second-to-last BP version.
Select the workload type
The workload types include OLTP, OLAP, HTAP, OBKV, and so on. It’s okay if you pick the wrong one. This choice only affects some parameter settings, and these parameters can all be changed later.
Select components
These components are all very necessary for production operations. In scenarios with OCP, these components work quietly in the background (except for OBConfigServer); in scenarios without OCP, the components’ roles come to the surface.
Everyone can understand all the components except OBConfigServer. OBConfigServer should be a “service” used for registering, querying, and storing the metadata of the OB RS. When manually deploying an OB cluster in the past, a drawback was that the RS had a hardcoded IP; with this service, OBProxy can hardcode the service’s API address and dynamically obtain the RS address of the OB cluster.
3.2.2 Node Configuration
Specify the database nodes and component nodes
There is only one node here, and you should try not to use the 127.0.0.1 address—use the actual IP instead.
Specify the deployment user
For the deployment username, use the commonly used admin user. Don’t use root!
Specify the software path configuration
For the deployment directory, use the commonly used default directory: /home/admin/obcedemo.
3.2.3 Cluster Configuration
Set the cluster password, data directory, and ports
For the mode configuration, if it’s a production server, choose “Maximum Utilization”; for a dev/test environment, choose “Minimum Available.” This is for people unfamiliar with OB. It’s okay if you pick the wrong one—you can still change the corresponding parameters later.
The OBShell port 2886 will be useful later.
Configure more parameters
Even for beginners, it’s recommended to configure these parameters. Otherwise, you may be surprised later when most of your disk and memory get used up. Each parameter here has its purpose; you can refer to the configuration in the figure.
Under a small-memory specification, set the parameter product_mode to False.
Configure component parameters
Mainly just set a password; keep all other parameters at their defaults.
The main thing is to limit OBProxy’s memory in this small-memory environment. In a production environment, you’d also increase this memory parameter proxy_mem_limited.
For the following parameters, enter them as prompted on the page. (Here vip_address has a front-end bug where the format check fails. You can collapse this “More Configuration” section to bypass the issue.)
3.2.4 Pre-Check
3.2.5 Start the Deployment
Click the “Deploy” button below.
Deployment successful
3.2.6 Create a Business Tenant
A successful creation looks like the following.
3.2.7 Tenant Connection
Verifying the tenant connection requires the obclient command. Let’s install it first.
mq@OBPILOT:~$ sudo obd cluster display obcedemo Get local repositories and plugins ok Open ssh connection ok Connect to ob-configserver ok +--------------------------------------------------------------------+ | ob-configserver | +----------------+------+----------------+----------+--------+-------+ | server | port | vip_address | vip_port | status | pid | +----------------+------+----------------+----------+--------+-------+ | x.x.x.x | 8080 | x.x.x.x | 8080 | active | 27382 | +----------------+------+----------------+----------+--------+-------+ curl -s 'http://x.x.x.x:8080/services?Action=GetObProxyConfig' Connect to observer x.x.x.x:2881 ok Wait for observer init ok +--------------------------------------------------+ | oceanbase-ce | +----------------+---------+------+-------+--------+ | ip | version | port | zone | status | +----------------+---------+------+-------+--------+ | x.x.x.x | 4.3.5.3 | 2881 | zone1 | ACTIVE | +----------------+---------+------+-------+--------+ obclient -hx.x.x.x -P2881 -uroot@sys -p'*******' -Doceanbase -A
Connect to obproxy ok +--------------------------------------------------------------------+ | obproxy-ce | +----------------+------+-----------------+-----------------+--------+ | ip | port | prometheus_port | rpc_listen_port | status | +----------------+------+-----------------+-----------------+--------+ | x.x.x.x | 2883 | 2884 | 2885 | active | +----------------+------+-----------------+-----------------+--------+ obclient -hx.x.x.x -P2883 -uroot@proxysys -p'***********' -Doceanbase -A
Connect to Obagent ok +-------------------------------------------------------------------+ | obagent | +----------------+--------------------+--------------------+--------+ | ip | mgragent_http_port | monagent_http_port | status | +----------------+--------------------+--------------------+--------+ | x.x.x.x | 8089 | 8088 | active | +----------------+--------------------+--------------------+--------+ Connect to Prometheus ok +----------------------------------------------------------+ | prometheus | +----------------------------+-------+------------+--------+ | url | user | password | status | +----------------------------+-------+------------+--------+ | http://x.x.x.x:9090 | admin | '*********' | active | +----------------------------+-------+------------+--------+ Connect to grafana ok +----------------------------------------------------------------------+ | grafana | +----------------------------------------+-------+------------+--------+ | url | user | password | status | +----------------------------------------+-------+------------+--------+ | http://x.x.x.x:3000/d/oceanbase | admin | '********' | active | +----------------------------------------+-------+------------+--------+ Connect to Alertmanager ok +------------------------------------------------------------+ | alertmanager | +----------------------------+-------+--------------+--------+ | url | user | password | status | +----------------------------+-------+--------------+--------+ | http://x.x.x.x:9093 | admin | '*********' | active | +----------------------------+-------+--------------+--------+ obshell program health check ok display ob-dashboard ok +---------------------------------------------------------+ | ob-dashboard | +----------------------------+------+------------+--------+ | url | user | password | status | +----------------------------+------+------------+--------+ | http://x.x.x.x:2886 | root | '********' | active | +----------------------------+------+------------+--------+
Trace ID: 6acb9326-8df4-11f0-8bd2-00155dd330c2 If you want to view detailed obd logs, please run: obd display-trace 6acb9326-8df4-11f0-8bd2-00155dd330c2
This command prints passwords in plaintext, which is bad. The asterisks (*) above are ones I edited. The product could actually set the password’s background and foreground colors to the same value, making the password not so “obvious” while still being copyable.
admin@OBPILOT:~/obcedemo/oceanbase$ cd oceanbase/ admin@OBPILOT:~/obcedemo/oceanbase$ tree bin -L 1 bin ├── import_srs_data.py -> /home/admin/.obd/repository/oceanbase-ce/4.3.5.3/01caa84d50b07cc5d09d3a34be2d543dd72e708f/bin/./import_srs_data.py ├── import_time_zone_info.py -> /home/admin/.obd/repository/oceanbase-ce/4.3.5.3/01caa84d50b07cc5d09d3a34be2d543dd72e708f/bin/./import_time_zone_info.py ├── observer -> /home/admin/.obd/repository/oceanbase-ce/4.3.5.3/01caa84d50b07cc5d09d3a34be2d543dd72e708f/bin/./observer └── obshell -> /home/admin/.obd/repository/oceanbase-ce/4.3.5.3/01caa84d50b07cc5d09d3a34be2d543dd72e708f/bin/./obshell
0 directories, 4 files
admin@OBPILOT:~/obcedemo/oceanbase$ ll store lrwxrwxrwx 1 admin admin 7 Sep 10 09:39 store -> /data/1/ admin@OBPILOT:~/obcedemo/oceanbase$ tree store store ├── clog -> /data/log1/clog ├── slog │ ├── server │ │ └── 1 │ ├── tenant_1 │ │ └── 1 │ ├── tenant_1001 │ │ └── 1 │ └── tenant_1002 │ └── 1 └── sstable └── block_file
7 directories, 5 files
Above are the OB-related directories. One thing worth noting about these directories is that the executable files and a few script files of observer, obproxy, and the related products are actually symbolic links; the real files live in the hidden directory ~/.obd. Never delete this hidden directory, and don’t assume that deleting the software directory cleans everything up.
The best way to clean up is to use the obd command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
admin@OBPILOT:~/obcedemo/oceanbase$ tree store/clog/tenant_1* -L 2 store/clog/tenant_1 └── 1 ├── log └── meta store/clog/tenant_1001 └── 1 ├── log └── meta store/clog/tenant_1002 ├── 1 │ ├── log │ └── meta └── 1001 ├── log └── meta
Above is the folder for the transaction log streams that were much discussed in OB 4.2. Each tenant gets one big folder.
OBSERVER itself is very simple—a single-process program that listens on 2881 and 2882. OBProxy is also a single-process program, listening on 2883, 2884, and 2885. The OBSHELL process listens on 2886. Each port has its own special purpose. For details, refer to the official documentation.
4.2 Experiencing OB_CONFIGSERVER
ob_configserver exists to make it convenient to obtain the RootService address of an OB cluster (multiple nodes) when there is no OCP. The OB cluster parameter obconfig_url is designed for this; in a production environment, this content is usually an OCP API address. If OCP is not deployed, you need a separate service to provide the read and write of this RootService metadata.
Usually the OB cluster parameter rootservice_list records the cluster’s RootService address. This parameter is specified during observer startup initialization. The drawback of this parameter is that it’s hardcoded: if the SYS tenant later changes machines, the RootService address changes too, but this parameter does not.
So the OB cluster also has a parameter obconfig_url, which is an API that can obtain the cluster’s RootService address. When the members of the OB cluster’s SYS tenant change (that is, when the RootService address changes), the OB cluster writes the new address through this API.
If OCP is not deployed, then deploy a separate service, ob_configserver. Below, let’s read the value through this API.
This is the displayed RootService address.
When OBProxy starts, it also needs the OB cluster’s RootService address. Likewise, OBProxy has two similar parameters. The Dashboard does not yet support viewing OBProxy parameters, so we go to the command line to view them.
admin@OBPILOT:~/obcedemo/obproxy$ mysql -h127.1 -uroot@proxysys -P2883 -p -c -A Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 786432005 Server version: 5.6.25
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h'forhelp. Type '\c' to clear the current input statement.
mysql> show proxyconfig like '%rootservice_list%'; +------------------+---------------------+------------------------------------------------------------------------------------------------------------------+-------------+---------------+-------+--------------+ | name | value | info | need_reboot | visible_level | range | config_level | +------------------+---------------------+------------------------------------------------------------------------------------------------------------------+-------------+---------------+-------+--------------+ | rootservice_list | x.x.x.x:2881 | a list of servers against which election candidate is checked for validation, format ip1:sql_port1;ip2:sql_port2 | true | SYS | | LEVEL_GLOBAL | +------------------+---------------------+------------------------------------------------------------------------------------------------------------------+-------------+---------------+-------+--------------+ 1 row inset (0.00 sec)
mysql> show proxyconfig like '%obproxy_config_server_url%'; +---------------------------+-------------------------------------------------------------+---------------------------------------+-------------+---------------+-------+--------------+ | name | value | info | need_reboot | visible_level | range | config_level | +---------------------------+-------------------------------------------------------------+---------------------------------------+-------------+---------------+-------+--------------+ | obproxy_config_server_url | http://x.x.x.x:8080/services?Action=GetObProxyConfig | url of config info(rs list and so on) | true | SYS | | LEVEL_GLOBAL | +---------------------------+-------------------------------------------------------------+---------------------------------------+-------------+---------------+-------+--------------+ 1 row inset (0.00 sec)
mysql>
Likewise, let’s look at the information returned when reading this API address.
This records the parameter value of obconfig_url for the OB cluster that this OBProxy cluster can connect to—that is, the API address mentioned earlier.
So these two APIs are both provided by the ob_configserver service.
Inspect the ob_configserver service
Below is the inspection of the ob_configserver service.
This parameter file specifies the VIP address, which can be an actual physical IP or a virtual IP. In a production environment, if the OB cluster has multiple nodes, this should be a VIP provided by a load balancer, with the backend pointing to the IP addresses where ob_configserver is deployed (which can be deployed independently on a VM or on the OB nodes).
The parameter file also indicates the location of the ob_configserver log.
By viewing the log, you can see this API being periodically called for reading (GET). If information is being written, it’s a POST. GET and POST are part of the HTTP protocol. If there’s a problem with the API, the details will be in this log.
The obshell process listens on port 2886, accessed via the HTTP protocol, at: http://x.x.x.x:2886/
This password is the root password of the sys tenant.
Cluster management
After logging in, the home page is cluster management, which only supports the current cluster.
At this point, the operations you can perform are parameter management and stopping the cluster.
Tenant management
Under tenant management, you can create new tenants. This is very common, so there’s no need to demonstrate it.
Under a tenant, you can create new databases and new users.
Software package management
You can upload software packages. Generally, you should upload the current OB cluster version and the obshell version software, so that you can upgrade later.
There is no entry point for deleting software packages; the feature still needs improvement.
Task center
OB-Dashboard’s operations also follow OCP’s framework, just in a more streamlined form. Operations are all carried out as task flows. The details of the task flows still look fairly rough at the moment.
Parameter management
This includes cluster parameter management and tenant parameter management.
Cluster parameters affect the entire cluster.
Tenant parameter management only affects the current tenant.
5. Summary
Overall, if OB Community Edition is for testing and learning, you can deploy it standalone on a laptop without deploying OCP, and use OB-Dashboard to do some simple basic operations.
Of course, performance monitoring and the like still await product improvements. For a production multi-node cluster, it’s still recommended to use a dedicated server to deploy a Community Edition OCP for operating the OB cluster.
Using the OBD command for operations is still too oriented toward technical detail, with a certain amount of complexity and risk.
Finally, we recommend the WeChat official account “Lao Ji’s Tech Talk,” run by Lao Ji, the OceanBase open-source lead. It continuously publishes a variety of technical content related to #Databases, #AI, and #Tech Architecture. Friends who are interested are welcome to follow!
“Lao Ji’s Tech Talk” not only hopes to keep bringing you valuable technical sharing, but also hopes to contribute to the open-source community together with everyone. If you appreciate the OceanBase open-source community, please light up a little star ✨! Every Star you give is the motivation behind our efforts.