DropVPS Team
Writer: Cooper Reagan
How to install n8n on RHEL 9

Table of Contents
What you will read?
- 1 Prepare RHEL 9 and firewall
- 2 Install Docker Engine
- 3 Create n8n project directories
- 4 Configure environment variables
- 5 Write the Docker Compose file
- 6 Launch n8n and verify
- 7 Make n8n run on boot (systemd)
- 8 Optional: HTTPS reverse proxy with NGINX
- 9 Upgrade and backup
- 10 Troubleshooting SELinux and permissions
Deploying n8n on RHEL 9 is straightforward and reliable with Docker and PostgreSQL. The setup below focuses on persistence, SELinux compatibility, and production readiness. Expect a clean directory layout, secure configuration, and service management with systemd. You’ll go from a fresh RHEL 9 box to a working n8n web UI with HTTPS support.
Prepare RHEL 9 and firewall
Update the OS, set the timezone, and open required ports. This ensures a secure baseline and network reachability for the n8n UI and optional HTTPS.
sudo dnf -y update
sudo timedatectl set-timezone UTC
sudo firewall-cmd --add-port=5678/tcp --permanent
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload
Install Docker Engine
RHEL 9 ships with Podman, but Docker Engine with the Compose plugin offers a simple path for n8n. Enable the Docker repository, install, and activate the service.
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
newgrp docker
Create n8n project directories
Set up a workspace with persistent volumes. Use UID/GID 1000 to match the n8n container’s user. SELinux relabeling will be applied later via Compose.
mkdir -p ~/n8n/data/n8n ~/n8n/data/postgres
sudo chown -R 1000:1000 ~/n8n/data/n8n
cd ~/n8n
Configure environment variables
Create an .env file to hold database credentials, host URLs, and security keys. The encryption key secures credentials stored by n8n.
openssl rand -hex 24
Copy the hex string, then create the file:
cat > .env <<'EOF'
# n8n core
GENERIC_TIMEZONE=UTC
N8N_HOST=your.domain.com
N8N_PORT=5678
N8N_PROTOCOL=https
WEBHOOK_URL=https://your.domain.com/
N8N_EDITOR_BASE_URL=https://your.domain.com/
N8N_ENCRYPTION_KEY=PASTE_HEX_KEY_HERE
N8N_SECURE_COOKIE=true
# Database (PostgreSQL)
DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=db
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=ChangeThisStrongPassword!
EOF
Write the Docker Compose file
Define Postgres and n8n services with persistent storage. The :Z suffix on volumes makes them SELinux-friendly on RHEL 9.
cat > docker-compose.yml <<'YML'
version: "3.8"
services:
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=${DB_POSTGRESDB_USER}
- POSTGRES_PASSWORD=${DB_POSTGRESDB_PASSWORD}
- POSTGRES_DB=${DB_POSTGRESDB_DATABASE}
volumes:
- ./data/postgres:/var/lib/postgresql/data:Z
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_POSTGRESDB_USER}"]
interval: 10s
timeout: 5s
retries: 5
n8n:
image: n8nio/n8n:latest
user: "1000:1000"
env_file:
- ./.env
depends_on:
db:
condition: service_healthy
ports:
- "${N8N_PORT}:5678"
volumes:
- ./data/n8n:/home/node/.n8n:Z
restart: unless-stopped
YML
Launch n8n and verify
Start the stack and confirm the application is reachable. The first web visit will prompt you to create the owner account.
docker compose up -d
docker compose ps
docker compose logs -f --tail=50 n8n
Optional health check:
curl -i http://127.0.0.1:5678/healthz
Example output:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 2
ok
Make n8n run on boot (systemd)
Create a systemd unit that encapsulates your Compose project. Replace USER with your username and adjust paths if needed.
sudo tee /etc/systemd/system/n8n.service >/dev/null <<'UNIT'
[Unit]
Description=n8n workflow automation (Docker Compose)
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
WorkingDirectory=/home/USER/n8n
Environment="COMPOSE_FILE=docker-compose.yml"
RemainAfterExit=yes
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now n8n
systemctl status n8n --no-pager
Optional: HTTPS reverse proxy with NGINX
Terminate TLS on the host with NGINX and Let’s Encrypt. This keeps n8n behind localhost while users access a secure domain.
sudo dnf -y install epel-release
sudo dnf -y install nginx certbot python3-certbot-nginx
sudo tee /etc/nginx/conf.d/n8n.conf >/dev/null <<'NGINX'
server {
listen 80;
server_name your.domain.com;
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
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-Proto $scheme;
client_max_body_size 50m;
proxy_read_timeout 3600;
}
}
NGINX
sudo systemctl enable --now nginx
sudo certbot --nginx -d your.domain.com -m [email protected] --agree-tos --redirect -n
Ensure your .env uses HTTPS and the domain for N8N_HOST, N8N_PROTOCOL, N8N_EDITOR_BASE_URL, and WEBHOOK_URL, then recreate n8n if changed.
docker compose up -d
Upgrade and backup
Pull new images and recreate containers with zero data loss. Back up both the n8n config directory and the Postgres database regularly.
cd ~/n8n
docker compose pull
docker compose up -d
docker image prune -f
Database backup (replace the container name if different):
docker ps --format '{{.Names}}'
docker exec -t n8n-db-1 pg_dump -U n8n n8n > ~/n8n/backup-$(date +%F).sql
tar -C ~/n8n -czf ~/n8n/files-$(date +%F).tar.gz data/n8n
Troubleshooting SELinux and permissions
If volumes fail due to SELinux, the :Z flag usually fixes it. For manual labeling, apply a persistent context and restore:
sudo dnf -y install policycoreutils-python-utils
sudo semanage fcontext -a -t container_file_t '~/n8n(/.*)?'
sudo restorecon -Rv ~/n8n
If n8n cannot write to its directory, ensure ownership is 1000:1000:
sudo chown -R 1000:1000 ~/n8n/data/n8n
Installation complete. You now have a production-friendly n8n on RHEL 9 with Docker, PostgreSQL, SELinux-safe volumes, and optional HTTPS. For more study, guidance, server purchases, and support, you can use dropvps. For more guides, visit dropvps.com