Running OpenSearch with Podman
Docker without the daemon. Same commands. Better security.
Why This Guide Exists
Most OpenSearch tutorials assume Docker. They give you commands that work. But what if you are on RHEL, Fedora, or CentOS? What if your organization banned Docker? What if you simply prefer rootless containers?
Podman is your answer.
This guide covers everything you need to run OpenSearch with Podman. Not just the commands. The reasoning behind them. The gotchas that will waste your afternoon. The password rules that reject seemingly strong passwords. The bash escaping that breaks your terminal.
All of it. From first principles.
What is Podman
Podman is a container engine developed by Red Hat. It runs containers the same way Docker does but without a central daemon process.
Every Docker command works with Podman. Replace docker with podman and everything runs the same way.
The differences that matter for OpenSearch.
No daemon means no single point of failure. Docker requires a background service running at all times. If dockerd crashes, all containers stop. Podman containers are regular processes. If one crashes, others keep running.
Rootless by default. Docker traditionally required root privileges. Podman runs containers as your regular user. This is better for security and better for shared servers where you do not have sudo access.
Systemd integration. Podman generates systemd unit files from containers. You can manage OpenSearch as a proper system service with start, stop, enable, and disable commands.
Drop in replacement. The podman command accepts the same flags as docker. You do not need to learn new syntax.
Prerequisites
Before we start, verify Podman is installed.
podman --versionYou should see output like podman version 4.9.4 or similar. If not, install it.
For Fedora and RHEL
sudo dnf install podmanFor Ubuntu and Debian
sudo apt install podmanFor macOS
brew install podman
podman machine init
podman machine startStarting OpenSearch
Here is the command that works.
podman run -d \
--name opensearch-node \
-p 9200:9200 \
-p 9600:9600 \
-e 'discovery.type=single-node' \
-e 'OPENSEARCH_INITIAL_ADMIN_PASSWORD=OpenSearch@2024Secure' \
-e 'OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m' \
opensearchproject/opensearch:latestLet me explain every part.
podman run creates and starts a new container.
-d runs it in detached mode. The container runs in the background and returns control to your terminal.
--name opensearch-node gives the container a name you can remember. Without this, Podman generates random names like quirky_einstein which are fun but not helpful when you have multiple containers.
-p 9200:9200 maps port 9200 from the container to your host machine. This is the REST API port. All your queries go through here.
-p 9600:9600 maps the performance analyzer port. Optional for learning but useful for monitoring.
-e ‘discovery.type=single-node’ tells OpenSearch to run as a single node cluster. Without this, OpenSearch waits forever looking for other nodes to form a cluster and never fully starts.
-e ‘OPENSEARCH_INITIAL_ADMIN_PASSWORD=...’ sets the admin password. This is mandatory since OpenSearch 2.12. The password must meet strict requirements which I will explain shortly.
-e ‘OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m’ controls JVM heap size. 512 megabytes is enough for learning. Production needs more.
opensearchproject/opensearch:latest specifies the container image. The latest tag gives you the newest version.
Live Link: https://asciinema.org/a/772348
The Password Problem
OpenSearch 3.x introduced strict password validation. This is where tutorials written for older versions fail you.
Your password must have all of these.
At least 8 characters.
At least one uppercase letter.
At least one lowercase letter.
At least one digit.
At least one special character.
Passes the zxcvbn strength algorithm.
That last requirement trips up most people. The zxcvbn algorithm detects common patterns and rejects passwords that look strong but are actually predictable.
These passwords fail validation.
Admin123! fails because Admin is a common word and 123 is a sequential pattern.
Password1@ fails because Password is literally a dictionary word.
Secure#2024 fails because secure is a dictionary word.
MyStr0ng!Pass fails because it uses predictable letter to number substitutions.
These passwords work.
OpenSearch@2024Secure works because the combination is random enough.
BlueTiger#Lamp42 works because random word combinations are strong.
Kx9$mPq2#vL8nR works because it is truly random.
The Bash Escaping Problem
Even with a valid password, bash can break your command. The exclamation mark is the culprit.
Try this command.
podman run -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=MyStr0ng!Pass"Bash returns event not found and refuses to run anything.
Why? Bash interprets ! as history expansion. When you type !Pass, bash tries to find a previous command starting with Pass and substitute it.
The fix is simple. Use single quotes instead of double quotes.
podman run -e 'OPENSEARCH_INITIAL_ADMIN_PASSWORD=OpenSearch@2024Secure'Single quotes tell bash to treat everything inside literally. No expansion. No interpretation. Just the text.
This applies to any password containing these characters.
! triggers history expansion.
$ triggers variable expansion.
` triggers command substitution.
# starts a comment if at certain positions.
Always use single quotes for passwords in shell commands.
Waiting for Startup
After running the podman command, OpenSearch needs time to initialize. This is not instant.
OpenSearch 3.x takes 60 to 90 seconds to fully start. The security plugin configures itself. Internal indices are created. The cluster state stabilizes.
Wait for it.
sleep 60Then check container status.
podman psYou should see output showing your container is up and running with ports mapped.
CONTAINER ID IMAGE STATUS PORTS
85c47eeb262f opensearchproject/opensearch:latest Up 2 minutes 0.0.0.0:9200->9200/tcpIf the STATUS column shows Exited instead of Up, something went wrong. Check the logs.
podman logs opensearch-nodeTesting the Connection
Now verify OpenSearch responds to requests.
curl -k -u 'admin:OpenSearch@2024Secure' https://localhost:9200The flags explained.
-k tells curl to skip SSL certificate verification. OpenSearch uses self signed demo certificates. Curl would reject them without this flag.
-u ‘admin:password’ provides HTTP Basic authentication credentials.
https://localhost:9200
is the endpoint. Note HTTPS not HTTP. OpenSearch enables SSL by default.
Expected response.
{
"name" : "opensearch-node",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "abc123...",
"version" : {
"distribution" : "opensearch",
"number" : "3.0.0"
},
"tagline" : "The OpenSearch Project: https://opensearch.org/"
}Check cluster health.
curl -k -u 'admin:OpenSearch@2024Secure' https://localhost:9200/_cluster/health?prettyLook for the status field. Green means healthy. Yellow means functional but replicas are unassigned. Red means problems.
Yellow is normal for single node setups. Replicas cannot be placed on the same node as primaries so they remain unassigned. This is expected behavior not an error.
Troubleshooting
Things will go wrong. Here is how to fix the common issues.
SSL_ERROR_SYSCALL when connecting
This error means OpenSearch is not ready yet or crashed during startup.
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:9200Check if the container is running.
podman ps -aIf status shows Exited, check the logs.
podman logs opensearch-nodeIf status shows Up, wait longer. OpenSearch 3.x can take 90 seconds on slower machines.
sleep 30
curl -k -u 'admin:OpenSearch@2024Secure' https://localhost:9200Container exits immediately
The container starts and stops within seconds. Check logs for the reason.
podman logs opensearch-nodeCommon causes.
Weak password. Look for “Weak password” in the logs. Choose a stronger password following the rules above.
Not enough memory. OpenSearch needs at least 2GB free RAM. Check with free -h and close other applications.
Port already in use. Another process is using port 9200. Check with ss -tlnp | grep 9200 and stop the conflicting service.
Permission denied errors
Podman runs rootless by default. Some systems need adjustments.
podman unshare chown -R 1000:1000 /path/to/dataOr run with the user namespace disabled for testing.
podman run --userns=keep-id ...Adding Dashboards
OpenSearch Dashboards provides a web interface for visualization and management. Running it alongside OpenSearch requires a shared network.
Create a network.
podman network create opensearch-netStart OpenSearch on this network.
podman run -d \
--name opensearch-node \
--network opensearch-net \
-p 9200:9200 \
-p 9600:9600 \
-e 'discovery.type=single-node' \
-e 'OPENSEARCH_INITIAL_ADMIN_PASSWORD=OpenSearch@2024Secure' \
-e 'OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m' \
opensearchproject/opensearch:latestWait for OpenSearch to start.
sleep 60Start Dashboards on the same network.
podman run -d \
--name opensearch-dashboards \
--network opensearch-net \
-p 5601:5601 \
-e 'OPENSEARCH_HOSTS=["https://opensearch-node:9200"]' \
opensearchproject/opensearch-dashboards:latestWait for Dashboards to start.
sleep 30Open http://localhost:5601 in your browser. Login with admin and your password.
Using Podman Compose
For repeatable setups, use Podman Compose. It reads the same YAML files as Docker Compose.
Install it.
pip install podman-composeCreate a directory for your project.
mkdir ~/opensearch-tutorial
cd ~/opensearch-tutorialCreate a file named podman-compose.yml with this content.
version: '3'
services:
opensearch-node:
image: opensearchproject/opensearch:latest
container_name: opensearch-node
environment:
- discovery.type=single-node
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=OpenSearch@2024Secure
- OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
- bootstrap.memory_lock=true
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
ports:
- 9200:9200
- 9600:9600
networks:
- opensearch-net
opensearch-dashboards:
image: opensearchproject/opensearch-dashboards:latest
container_name: opensearch-dashboards
environment:
- OPENSEARCH_HOSTS=["https://opensearch-node:9200"]
ports:
- 5601:5601
networks:
- opensearch-net
depends_on:
- opensearch-node
networks:
opensearch-net:Start everything.
podman-compose up -dCheck status.
podman-compose psStop everything.
podman-compose downPerformance Tuning
The defaults work for learning. Production needs tuning.
Heap size controls how much memory the JVM uses. Set it to 50% of available RAM but never more than 32GB. Always set minimum and maximum to the same value.
For 8GB RAM machine use 4GB heap.
-e 'OPENSEARCH_JAVA_OPTS=-Xms4g -Xmx4g'For 16GB RAM machine use 8GB heap.
-e 'OPENSEARCH_JAVA_OPTS=-Xms8g -Xmx8g'Memory lock prevents swapping. Swapping destroys search performance. Enable it.
-e 'bootstrap.memory_lock=true' \
--ulimit memlock=-1:-1File descriptors limit how many files OpenSearch can open. The default is too low.
--ulimit nofile=65536:65536Complete production ready command.
podman run -d \
--name opensearch-node \
-p 9200:9200 \
-p 9600:9600 \
-e 'discovery.type=single-node' \
-e 'OPENSEARCH_INITIAL_ADMIN_PASSWORD=OpenSearch@2024Secure' \
-e 'OPENSEARCH_JAVA_OPTS=-Xms4g -Xmx4g' \
-e 'bootstrap.memory_lock=true' \
--ulimit memlock=-1:-1 \
--ulimit nofile=65536:65536 \
opensearchproject/opensearch:latestCleanup
When you are done experimenting.
Stop containers.
podman stop opensearch-node opensearch-dashboardsRemove containers.
podman rm opensearch-node opensearch-dashboardsOr with compose.
podman-compose downRemove unused images to free disk space.
podman image pruneRemove unused volumes.
podman volume pruneInteractive guide available at https://opensearch.9cld.com


