{"id":1027,"date":"2026-11-07T13:00:00","date_gmt":"2026-11-07T13:00:00","guid":{"rendered":"https:\/\/vpslake.com\/blog\/?p=1027"},"modified":"2026-11-07T13:00:00","modified_gmt":"2026-11-07T13:00:00","slug":"install-bludit-nginx-rocky-linux-8","status":"publish","type":"post","link":"https:\/\/vpslake.com\/blog\/2026\/11\/07\/install-bludit-nginx-rocky-linux-8\/","title":{"rendered":"How to Install Bludit CMS on Rocky Linux 8 with Nginx"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">To install Bludit CMS with Nginx on Rocky Linux 8, you will configure PHP-FPM, SELinux, firewalld, and HTTPS before opening Bludit\u2019s browser installer. A fresh VPS with DNS ready should be publishing a working flat-file site in about 15 minutes, without MariaDB or MySQL.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>A fresh Rocky Linux 8.10 VPS with at least 1 GB RAM, 10 GB of free disk space, and a public IPv4 address.<\/li>\n\n\n<li>Root access or a sudo-enabled user connected over SSH. The commands below use <code>sudo<\/code>.<\/li>\n\n\n<li>A domain such as <code>YOUR_DOMAIN<\/code> with an A record pointing to the VPS. Keep TCP ports 80 and 443 available for the site and certificate validation.<\/li>\n\n\n<li>A strong, unique Bludit administrator password stored in a password manager.<\/li>\n\n\n<li>A <a href=\"https:\/\/vpslake.com\/buy-vps\">VPSLake Linux VPS<\/a> is suitable for a small Bludit site.<\/li>\n\n\n<li><a href=\"https:\/\/docs.bludit.com\/en\/getting-started\/requirements\" target=\"_blank\" rel=\"noopener\">Bludit\u2019s requirements<\/a> call for PHP 8.0 or newer plus the <code>mbstring<\/code>, <code>gd<\/code>, <code>dom<\/code>, and <code>json<\/code> modules; this guide uses Rocky Linux 8\u2019s PHP 8.2 AppStream.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Install Nginx, PHP 8.2, and firewalld<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Rocky Linux 8 uses DNF module streams, so select the PHP and Nginx versions before installing PHP-FPM and the extensions Bludit needs.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo dnf update -y\nsudo dnf module reset nginx php -y\nsudo dnf module enable nginx:1.24 php:8.2 -y\nsudo dnf install -y epel-release\nsudo dnf install -y firewalld nginx php php-fpm php-cli php-curl php-gd php-mbstring php-opcache php-xml php-zip curl unzip bind-utils certbot python3-certbot-nginx policycoreutils-python-utils\nsudo sed -ri 's\/^[;[:space:]]*user[[:space:]]*=.*\/user = nginx\/; s\/^[;[:space:]]*group[[:space:]]*=.*\/group = nginx\/; s\/^[;[:space:]]*listen\\.owner[[:space:]]*=.*\/listen.owner = nginx\/; s\/^[;[:space:]]*listen\\.group[[:space:]]*=.*\/listen.group = nginx\/' \/etc\/php-fpm.d\/www.conf\nsudo systemctl enable --now firewalld nginx php-fpm\nsudo systemctl restart php-fpm\nphp -v\nphp -m | grep -E 'dom|gd|json|mbstring'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The version should begin with PHP 8.2, and the module check should print <code>dom<\/code>, <code>gd<\/code>, <code>json<\/code>, and <code>mbstring<\/code> on separate lines. PHP-FPM\u2019s Rocky Linux socket is <code>\/run\/php-fpm\/www.sock<\/code>; the Nginx server block will use that path.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Download Bludit and limit write access<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bludit stores pages, users, settings, and uploads as files, so protect the application code and give PHP-FPM write access only to <code>bl-content<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Download the current Bludit 3.x release from the official distribution URL and unpack it under <code>\/var\/www<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/tmp\ncurl -fL -o bludit-3.22.0.zip https:\/\/www.bludit.com\/releases\/bludit-3-22-0.zip\nunzip -q bludit-3.22.0.zip -d \/tmp\nsudo install -d \/var\/www\/bludit\nsudo cp -a \/tmp\/bludit-3.22.0\/. \/var\/www\/bludit\/\nsudo chown -R root:nginx \/var\/www\/bludit\nsudo find \/var\/www\/bludit -type d -exec chmod 0750 {} \\;\nsudo find \/var\/www\/bludit -type f -exec chmod 0640 {} \\;\nsudo chown -R nginx:nginx \/var\/www\/bludit\/bl-content\nsudo find \/var\/www\/bludit\/bl-content -type d -exec chmod 0770 {} \\;\nsudo find \/var\/www\/bludit\/bl-content -type f -exec chmod 0660 {} \\;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The archive is pinned to 3.22.0 so a later release cannot silently alter the files during this setup. Do not make the entire document root writable: Bludit\u2019s content directory is the part that must change when you create pages or upload media.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Rocky Linux 8 normally runs SELinux in enforcing mode. Add persistent labels for read-only application files and the writable content tree, then apply them:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo semanage fcontext -a -t httpd_sys_content_t '\/var\/www\/bludit(\/.*)?'\nsudo semanage fcontext -a -t httpd_sys_rw_content_t '\/var\/www\/bludit\/bl-content(\/.*)?'\nsudo restorecon -Rv \/var\/www\/bludit<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Create the Nginx server block<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bludit\u2019s router sends unknown paths to <code>index.php<\/code>, while the protected locations stop browsers from reading JSON content or executing PHP from the core directory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>\/etc\/nginx\/conf.d\/bludit.conf<\/code>, replacing <code>YOUR_DOMAIN<\/code> with the hostname in DNS:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\n    listen 80;\n    listen [::]:80;\n    server_name YOUR_DOMAIN;\n\n    root \/var\/www\/bludit;\n    index index.php;\n    client_max_body_size 16m;\n\n    location ^~ \/bl-content\/databases\/ { deny all; }\n    location ^~ \/bl-content\/pages\/ { deny all; }\n    location ^~ \/bl-content\/workspaces\/ { deny all; }\n    location ^~ \/bl-content\/tmp\/ { deny all; }\n    location ~* ^\/bl-kernel\/.*\\.php$ { deny all; }\n\n    location \/ {\n        try_files $uri $uri\/ \/index.php?$args;\n    }\n\n    location ~ \\.php$ {\n        try_files $uri =404;\n        include \/etc\/nginx\/fastcgi_params;\n        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n        fastcgi_param HTTPS $https if_not_empty;\n        fastcgi_pass unix:\/run\/php-fpm\/www.sock;\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Write the file with your editor, then test the complete Nginx configuration before reloading it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo vi \/etc\/nginx\/conf.d\/bludit.conf\nsudo nginx -t\nsudo systemctl reload nginx<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The test should finish with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nginx: the configuration file \/etc\/nginx\/nginx.conf syntax is ok\nnginx: configuration file \/etc\/nginx\/nginx.conf test is successful<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This server block deliberately starts with HTTP. Certbot will add the TLS listener after the domain resolves, so you do not have to reference certificate files that do not exist yet. Bludit\u2019s <a href=\"https:\/\/docs.bludit.com\/en\/webservers\/nginx\" target=\"_blank\" rel=\"noopener\">official Nginx configuration<\/a> documents the front-controller rule and protected directories.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Open the firewall and enable HTTPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Allow SSH for administration, HTTP for Let\u2019s Encrypt validation, and HTTPS for the finished website; repeat these ports in any firewall provided by your VPS host.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo firewall-cmd --permanent --zone=public --add-service=ssh\nsudo firewall-cmd --permanent --zone=public --add-service=http\nsudo firewall-cmd --permanent --zone=public --add-service=https\nsudo firewall-cmd --reload\nsudo firewall-cmd --list-services\ndig +short YOUR_DOMAIN<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>dig<\/code> result must contain the VPS public IP before you request a certificate. Replace <code>YOUR_EMAIL<\/code> with an address that receives renewal notices, then run Certbot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo certbot --nginx --redirect --agree-tos --no-eff-email -m YOUR_EMAIL -d YOUR_DOMAIN<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Certbot should report that the certificate was successfully deployed. It will create the HTTPS server block and redirect normal HTTP requests to HTTPS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Complete the Bludit browser installer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The web installer writes the site configuration and administrator account into <code>bl-content<\/code>, so it does not ask for database host, user, or password values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Open <code>https:\/\/YOUR_DOMAIN<\/code> in a browser. Select the language, enter a site name, choose an administrator username, and create a long unique password. Submit the form, sign in at the administrator URL shown by Bludit, and publish a small test page with an image.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the installer reports that content is not writable, stop and repair ownership and the SELinux label before submitting the form again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo chown -R nginx:nginx \/var\/www\/bludit\/bl-content\nsudo restorecon -Rv \/var\/www\/bludit\/bl-content\nsudo systemctl restart php-fpm<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Verify the Bludit installation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run these checks from SSH and then load the site in a private browser window. The private window confirms the certificate and administrator session without a cached HTTP redirect.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl is-active nginx php-fpm firewalld\nsudo nginx -t\nphp -m | grep -E 'dom|gd|json|mbstring'\ncurl -fsSI https:\/\/YOUR_DOMAIN | head -n 1\ncurl -fsS -o \/dev\/null -w '%{http_code}\\n' https:\/\/YOUR_DOMAIN\/bl-content\/databases\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected results are <code>active<\/code> for all three services, a successful Nginx test, the four PHP modules, an HTTPS status such as <code>HTTP\/2 200<\/code>, and <code>403<\/code> for the protected database path. A <code>302<\/code> redirect or an installer page is normal if you have not finished the browser setup.<\/p>\n\n\n\n<aside class=\"vl-element vl-cta-banner\" aria-label=\"Host Bludit on Rocky\">\n\t<div class=\"vl-cta-banner__content\">\n\t\t<p class=\"vl-cta-banner__eyebrow\">Rocky Linux VPS<\/p>\n\t\t<h3 class=\"vl-cta-banner__title\">Host Bludit on Rocky<\/h3>\n\t\t<p class=\"vl-cta-banner__text\">Launch a secure Bludit site with Nginx and HTTPS on a Rocky Linux 8 VPS.<\/p>\n\t<\/div>\n\t<a class=\"vl-cta-banner__button\" href=\"\/buy-vps\" aria-label=\"View Linux VPS plans\">View Linux VPS plans<\/a>\n<\/aside>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">502 Bad Gateway<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Nginx cannot reach PHP-FPM, commonly because the service is stopped or the socket path does not match the server block. Check <code>sudo systemctl status php-fpm<\/code>, then compare <code>listen =<\/code> in <code>\/etc\/php-fpm.d\/www.conf<\/code> with <code>\/run\/php-fpm\/www.sock<\/code> and restart PHP-FPM after correcting it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>Permission denied<\/code> in the Nginx error log<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Unix socket or its SELinux context is preventing Nginx from contacting PHP-FPM. Confirm the socket with <code>sudo ls -lZ \/run\/php-fpm\/www.sock<\/code>, verify the pool uses the <code>nginx<\/code> user and group, and run <code>sudo systemctl restart php-fpm<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The home page works but a new page returns 404<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The request is probably using a different server block or the front-controller fallback was edited. Run <code>sudo nginx -T | grep -A8 -B2 'server_name YOUR_DOMAIN'<\/code>, confirm <code>try_files $uri $uri\/ \/index.php?$args;<\/code>, and reload Nginx after fixing the file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Certbot reports a timeout or failed validation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The DNS record may still point elsewhere, or port 80 may be blocked by firewalld or an upstream VPS firewall. Compare <code>dig +short YOUR_DOMAIN<\/code> with the server\u2019s public IP, allow HTTP in both firewalls, and run Certbot again after DNS updates.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hardening and maintenance<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Back up <code>\/var\/www\/bludit<\/code>, especially <code>bl-content<\/code>, before upgrades; it contains the site\u2019s pages, users, settings, and uploads.<\/li>\n\n\n<li>Keep Rocky Linux, PHP, Nginx, and Bludit updated, and take a backup before replacing files within the Bludit 3.x series.<\/li>\n\n\n<li>Test renewal with <code>sudo certbot renew --dry-run<\/code> after HTTPS is working.<\/li>\n\n\n<li>Keep SELinux enforcing and give write access only to directories that Bludit or a trusted plugin actually needs.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Why does this guide enable PHP 8.2 instead of Rocky\u2019s default stream?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Rocky Linux 8\u2019s default PHP stream is older, while its AppStream includes PHP 8.2. Bludit\u2019s requirements call for PHP 8.0 or newer, so PHP 8.2 provides a compatible supported stream without adding a third-party repository.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does Bludit need MariaDB or MySQL?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. Bludit is a flat-file CMS and keeps content and configuration beneath <code>bl-content<\/code>. Your backup plan should therefore include the complete application directory rather than only a database dump.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can I use an IP address instead of a domain?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You can test the HTTP server by IP, but a domain is the practical choice for a public installation. Let\u2019s Encrypt cannot issue the normal certificate used here for an arbitrary server IP, and the installer\u2019s HTTPS URL should use the hostname you configured.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Which Bludit directory needs the most protection?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Protect <code>bl-content\/databases<\/code>, <code>bl-content\/pages<\/code>, <code>bl-content\/workspaces<\/code>, and <code>bl-content\/tmp<\/code> from direct web requests because they contain site data. The Nginx rules also deny PHP execution beneath <code>bl-kernel<\/code>, reducing the impact of an accidental upload or misconfiguration.<\/p>\n\n\n\n<script type=\"application\/ld+json\">{\"@context\": \"https:\/\/schema.org\", \"@type\": \"FAQPage\", \"mainEntity\": [{\"@type\": \"Question\", \"name\": \"Why does this guide enable PHP 8.2 instead of Rocky\u2019s default stream?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Rocky Linux 8\u2019s default PHP stream is older, while its AppStream includes PHP 8.2. Bludit\u2019s requirements call for PHP 8.0 or newer, so PHP 8.2 provides a compatible supported stream without adding a third-party repository.\"}}, {\"@type\": \"Question\", \"name\": \"Does Bludit need MariaDB or MySQL?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. Bludit is a flat-file CMS and keeps content and configuration beneath `bl-content`. Your backup plan should therefore include the complete application directory rather than only a database dump.\"}}, {\"@type\": \"Question\", \"name\": \"Can I use an IP address instead of a domain?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"You can test the HTTP server by IP, but a domain is the practical choice for a public installation. Let\u2019s Encrypt cannot issue the normal certificate used here for an arbitrary server IP, and the installer\u2019s HTTPS URL should use the hostname you configured.\"}}, {\"@type\": \"Question\", \"name\": \"Which Bludit directory needs the most protection?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Protect `bl-content\/databases`, `bl-content\/pages`, `bl-content\/workspaces`, and `bl-content\/tmp` from direct web requests because they contain site data. The Nginx rules also deny PHP execution beneath `bl-kernel`, reducing the impact of an accidental upload or misconfiguration.\"}}]}<\/script>\n\n","protected":false},"excerpt":{"rendered":"Install Bludit CMS with Nginx on Rocky Linux 8 using PHP 8.2, SELinux, firewalld, and HTTPS. Launch a secure flat-file website without a database.","protected":false},"author":1,"featured_media":1028,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_singular_sidebar":"","csco_page_header_type":"","csco_page_load_nextpost":"","footnotes":""},"categories":[5,9],"tags":[127,129,125,128,105],"class_list":["post-1027","post","type-post","status-publish","format-standard","has-post-thumbnail","category-guides","category-vps-hosting","tag-bludit","tag-cms","tag-nginx","tag-php-fpm","tag-rocky-linux-8","cs-entry"],"_links":{"self":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/1027","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/comments?post=1027"}],"version-history":[{"count":1,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/1027\/revisions"}],"predecessor-version":[{"id":3927,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/1027\/revisions\/3927"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media\/1028"}],"wp:attachment":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media?parent=1027"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/categories?post=1027"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/tags?post=1027"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}