Joomla Installation and the Public Folder
|
This content was generated with the assistance of AI and should be verified against the official Joomla documentation before being relied on in production. This sub-section’s Joomla bibliography lists the reference material consulted while preparing these pages. |
This page was written against Joomla 6.2.x and PHP 8.3+ and checked on 2026-10-30. It follows the installation of the
fictitious Tallpine Hiking Club site from an empty directory to a logged-in administrator on a site with clean URLs. It
covers the download, the web installer, the command-line installer used for scripted and containerised set-ups, the
public folder option that arrived in Joomla 5.0, the .htaccess file, search-engine-friendly (SEF) URLs and what to do
in the first ten minutes after logging in.
Who needs this page: the site builder who installs a site, the administrator who decides how the code tree is exposed to the web, and the developer who scripts installations for local environments and CI. Hosting choices and the full requirements matrix are in Requirements and Hosting; the web server side (virtual hosts, TLS, reverse proxy) is in Web Server, Reverse Proxy and HTTPS.
Before installing
Requirements in one table
The Joomla Developer Manual lists three columns for every dependency: recommended, supported and minimum. A version between the minimum and the supported value works at your own risk. For Joomla 6.x the Manual gives:
| Software | Recommended | Supported | Minimum |
|---|---|---|---|
PHP |
8.4 |
8.3.0 |
8.3.0 |
MySQL |
8.4 |
8.0.13 |
8.0.13 |
MariaDB |
12.0 |
10.6 |
10.4 |
PostgreSQL |
17.6 |
14.0 |
12.0 |
Apache |
2.4 |
2.4 |
not listed |
Nginx |
1.29 |
1.26 |
not listed |
Microsoft IIS |
10 |
10 |
not listed |
Required PHP extensions are json, simplexml, dom, zlib and gd, plus one database driver (mysqlnd, pdo_mysql
or pdo_pgsql); mbstring is recommended. A PHP memory limit of 256 MB is recommended. SEF URL rewriting needs
mod_rewrite on Apache or the URL Rewrite Module on IIS. Microsoft SQL Server has not been supported since Joomla 4.0.
The Manual and the upgrade guide disagree on the database minimums for 6.x. The Technical Requirements page enforces MariaDB 10.4 and PostgreSQL 12 and supports MariaDB 10.6 and PostgreSQL 14, while the upgrade guide states 10.6 and 14. Treat the higher figures as the safe target for a new site; since the minimum requirements rise only in the first release of a major, a 6.x site will not suddenly demand newer software during the 6.x series.
The User Guide’s installation page adds practical PHP limits for the installer itself: memory_limit of 256M,
upload_max_filesize and post_max_size of 64M, and max_execution_time of 30 seconds.
Which platform to start on
Joomla 6.2 is the current minor. Joomla 5.x receives security fixes only (5.4.10 was the last bugfix release; security support runs until 2027-10-12), and Joomla 4.x and 3.x are end of life. A new site therefore starts on 6.x. The release cycle that explains these dates is in Versions, Release Cycle and Support.
Older books and tutorials show an installation of Joomla 3.x or 4.x. Joomla! 4 Masterclass (Packt, 2023) targets 4.x and does not cover requirements or installation in detail; Developing Extensions for Joomla! 5 (Packt, 2023) targets 5.0 with PHP 8.2. Neither mentions the public folder tooling, the Automated Core Updates opt-out screen or the PHP 8.3 minimum. See Where Older Books and Tutorials Are Outdated.
Overview of the installation
Downloading the full package
Download the Joomla full package from the official Download Joomla page on joomla.org. The full package is a ZIP (or
tar.gz) archive of the complete code tree, including the installation directory that holds the web installer. It is
different from the update package (for upgrading an existing site) and from the Docker image or the Git repository.
Installing from the Git repository needs composer install and npm install first; a checkout is for contributors, not
for production.
Verify the download before using it. Release announcements on joomla.org publish the checksums of each package, so compare a local checksum with the published one:
# Download the full package from the Download Joomla page, then:
sha256sum Joomla_6.2.0-Stable-Full_Package.zip # compare with the value published with the release
mkdir -p /var/www/tallpine
unzip Joomla_6.2.0-Stable-Full_Package.zip -d /var/www/tallpine
The file name above is an example; use the name of the package you downloaded and the checksum published for that
release. Extract the contents of the archive, not a wrapping folder: if the archive is extracted into a folder named
Joomla inside the web root, the site is served at example.com/Joomla instead of the domain root. Use lowercase folder
names without spaces. The ZIP can be deleted after extraction.
Permissions
The web server user must be able to write while installing (the installer writes configuration.php and removes its own
directory). A conventional layout is directories 755 and files 644, with the site owned by the deploy user and only the
folders that must be writable (administrator/cache, cache, tmp, logs, images) made writable by the web server
user. Avoid 777 on shared hosts: any other account on the machine can then write PHP files into your tree.
The web installer
Browse to the domain (or http://localhost/ locally). If configuration.php does not exist, Joomla redirects to the
installer in the installation directory. The installer is a single page with a few steps; the labels below are taken from
the Joomla 6.2 installer.
Language
The language list is preselected from the browser. This is the language of the installer and of the first Super User screens. Extra languages for the site are installed at the end of the process (see below), so a German site for the Tallpine club still starts from English and adds German on the final screen.
Step 1: site name
Site Name is the name of the site. It is stored in Global Configuration and can be changed later (see Global Configuration). The next button is labelled Setup Login Data.
Step 2: the Super User
The login data screen asks for four values:
-
Real Name, the display name of the Super User
-
Super User account username, the user name for the login; avoid
admin, because it is the first name a password-guessing script tries -
Admin Password, a strong password that you can change later in the profile screen
-
Super User Email Address, used for password reset and system mail
The Super User is the account that bypasses the permission system; treat it as a break-glass account and create separate named administrators for day-to-day work. Multi-factor authentication for that account is covered in Security Hardening, MFA and Passkeys.
Step 3: the database
The database screen contains the fields defined in the installer form installation/forms/setup.xml:
| Field | Meaning |
|---|---|
Database Type |
|
Hostname |
Defaults to |
Username, Password |
The credentials of the database user, not the Super User password |
Database Name |
An existing, empty database (the installer does not create it) |
Table Prefix |
Generated at random by default; it must start with a letter, may contain alphanumerics and must end in an underscore. Tables with the same prefix that already exist are renamed with a |
Connection Encryption |
Default (server controlled), One-way authentication or Two-way authentication. The latter two show fields for the CA file, certificate, private key, cipher suite and Verify Server Certificate |
The encryption modes need TLS enabled on the database server. The installer reports specific messages when the server does
not support encryption, when a file path is wrong, when it silently fell back to an unencrypted connection, or when the host
is localhost (use 127.0.0.1 or ::1 for encrypted connections). Leave the default unless your database provider tells
you otherwise.
Common errors on this screen: a wrong user or password; a database user without the privileges to create tables; a missing
pdo_mysql/mysqlnd extension, which removes the driver from the list; and typing the Super User password where the
database password belongs. The settings cannot be changed afterwards without editing configuration.php (see
configuration.php and .htaccess).
Pressing Install Joomla runs the installation with a progress bar: the installer creates the tables, populates the base
data, the supported extensions and the localisation data, and writes configuration.php. If installing fails halfway,
delete the half-created tables (or drop and recreate the database) and delete configuration.php before starting again,
otherwise the installer thinks the site exists.
The Congratulations screen
When the installation finishes, the installer shows Congratulations! Your Joomla site is ready. with the buttons Open Administrator and Open Site. This screen also carries the options that are easy to miss.
Install Additional Languages lets you install language packs before leaving the installer. The User Guide recommends no more than three at once because more can time out. After installation you choose the default administrator and site language in a table and press the set-default button. Language packs can be a different minor version than the core; later updates appear in the extension updater. Multilingual configuration (content languages, associations, language switcher) continues in Multilingual Sites.
Automated Updates is shown as its own panel with a Disable Automated Updates button. This is the installer’s opt-out. Its text explains that Joomla updates itself for minor and patch releases and that the feature registers the site with the update service run by the Joomla Project, which receives the site URL, the PHP version, the database type and version, the CMS version and the server operating system type and version. Leaving the panel alone keeps the feature on. The facts to know about Automated Core Updates:
-
It was introduced in Joomla 5.4 and 6.0 and covers minor, patch and security releases.
-
A server at joomla.org triggers the site through Joomla Update web-service endpoints; the site then performs the update itself. The site must therefore be publicly reachable.
-
It is on by default for new installs (this panel is the opt-out) and off for upgraded sites.
-
It requires the Default update channel and "Stable" minimum stability.
-
Core update packages have been verified with TUF (The Update Framework) since Joomla 5.1.
An intranet site, a site behind HTTP authentication, or a site whose deployments are controlled by a pipeline normally disables the feature, because the update server cannot reach it or because the update should go through staging first. The setting can be changed later in the Joomla Update options. The full discussion, including how to re-enable it, is in Updating Joomla and Automated Core Updates.
A Recommended Settings table may also be shown when PHP settings differ from what Joomla recommends. These are recommendations, not blockers, but resolve them on a production host.
Removing the installation folder
The installation directory contains the installer itself. Leaving it on a live site is dangerous because it can be
abused to reinstall the site. In the production package the installer removes the directory when the process completes
(the User Guide notes that its screenshot comes from a developer installation). If the installer cannot delete it, for
example because of file ownership, it reports that the folder could not be deleted and asks you to delete it manually.
Check that the directory is really gone:
cd /var/www/tallpine
test -d installation && rm -r installation && echo "installation folder removed"
ls configuration.php # created by the installer
Never leave the installer reachable on a production host, and keep configuration.php out of version control and
backups that are not encrypted: it holds the database password and the site secret.
Installing from the command line
Joomla ships a non-interactive installer, installation/joomla.php, used by the project’s own development container. It
accepts the same fields as the web installer as options, plus the public-folder option. Passwords come from the
environment so that they do not appear in shell history or in committed scripts:
php installation/joomla.php install \
--site-name="Tallpine Hiking Club" \
--admin-user="Tallpine Admin" \
--admin-username="tp_root" \
--admin-password="$TALLPINE_ADMIN_PASSWORD" \
--admin-email="admin@tallpine.example" \
--db-type="mysqli" \
--db-host="db" \
--db-name="tallpine" \
--db-user="tallpine" \
--db-pass="$TALLPINE_DB_PASSWORD" \
--db-prefix="tp_" \
--db-encryption="0" \
--public-folder=""
Run the command from the code tree. When the options are missing the command asks for them interactively. After a
successful run the command deletes the installation directory and, when --public-folder is not empty, creates the
public folder. The resulting site is administered with php cli/joomla.php; see
The Joomla Command Line Interface.
A local Docker Compose environment
For a reproducible local installation, run Joomla with MariaDB and a mail catcher. The Compose file below uses the
official joomla image at a pinned tag, MariaDB 11.4 and Mailpit. The credentials come from an .env file that is not
committed:
# compose.yaml
services:
joomla:
image: joomla:6.2-php8.3-apache
ports:
- "8080:80"
environment:
JOOMLA_DB_HOST: db
JOOMLA_DB_NAME: tallpine
JOOMLA_DB_USER: tallpine
JOOMLA_DB_PASSWORD: ${TALLPINE_DB_PASSWORD}
volumes:
- joomla_data:/var/www/html
depends_on:
- db
db:
image: mariadb:11.4
environment:
MARIADB_DATABASE: tallpine
MARIADB_USER: tallpine
MARIADB_PASSWORD: ${TALLPINE_DB_PASSWORD}
MARIADB_RANDOM_ROOT_PASSWORD: "1"
volumes:
- db_data:/var/lib/mysql
mailpit:
image: axllent/mailpit:v1.21
ports:
- "8025:8025"
volumes:
joomla_data:
db_data:
Source: Docker Official Image: joomla
Open http://localhost:8080/ and run the web installer with the host db. Mailpit’s web interface on port 8025 catches
the mail Joomla sends. The container topics (volumes, build, health checks) are expanded in
Local Development with Docker.
The public folder
Why it exists
In a classic installation the whole code tree is inside the document root: libraries, plugins, administrator,
configuration.php, logs, tmp and cache are all reachable below the web server’s root. Security therefore depends
on every PHP file refusing to run when requested directly (the familiar guard at the top of a file) and on .htaccess
rules. A public folder inverts the model: the web server’s document root points at a small directory that holds only
what a browser must reach, and everything else (including configuration.php) lives outside the root where no URL maps to
it.
The feature arrived with Joomla 5.0. The class that creates the folder is annotated @since 5.0.0 in the source tree. As
of the check date the User Guide and the Developer Manual do not have a page about it, so the source tree is the
reference for this section. Books published for Joomla 3, 4 and 5.0 do not describe it.
What the public folder contains
Joomla creates the folder with the helper class Joomla\CMS\Helper\PublicFolderGeneratorHelper. The generated tree is:
tallpine/ code tree: JPATH_ROOT, outside the web root
administrator/ api/ cli/ components/ includes/ layouts/ libraries/
plugins/ templates/ modules/ ...
configuration.php
images/ files/ uploaded media (real directories)
media/ static assets (real directory)
public/ web server document root: JPATH_PUBLIC
index.php loader for the site
defines.php generated constants
robots.txt copied from the root (or robots.txt.dist)
.htaccess copied from the root (or htaccess.txt)
administrator/index.php loader for the administrator
administrator/components/com_joomlaupdate/extract.php symlink
api/index.php loader for the Web Services API
media/ symlink to ../media
images/ files/ symlinks to the local filesystem directories
The generated files are small. public/defines.php sets the three constants that tell Joomla where things are, and each
index.php records its application path, loads the defines and then hands over to the real index.php in the code tree:
<?php
// public/defines.php (generated, shown for a public folder one level below the root)
define('JPATH_ROOT', dirname(__DIR__));
define('JPATH_PUBLIC', JPATH_ROOT . '/public');
define('JPATH_BASE', JPATH_ROOT . $applicationPath);
// public/index.php (generated)
$applicationPath = '';
require_once __DIR__ . '/defines.php';
unset($applicationPath);
require_once JPATH_BASE . '/index.php';
The code tree’s own index.php loads an optional root-level defines.php first (when it exists) and then
includes/defines.php, which defines each path constant only when it has not been defined yet. That is why constants set
by the generated defines.php win. Without them, JPATH_PUBLIC defaults to JPATH_ROOT, which is exactly the classic
layout.
| Constant | Meaning |
|---|---|
|
The code tree (where |
|
The directory the web server serves; used for URLs to static files and for the router |
|
The application being executed: the root for the site, |
When the destination is given as a relative path, the helper builds JPATH_ROOT from dirname(__DIR__) repeated once
per path segment, so the site keeps working when the whole tree is moved or mounted at another path. When the destination
is absolute (for example /srv/www/tallpine-public), the helper writes the absolute paths into defines.php, which
suits a deployment where the code tree is released into a versioned directory and the public folder is fixed.
Creating the folder
Two routes exist. At install time, give the installer the option (the option is available in the command-line installer; the web installer form does not render the field):
php installation/joomla.php install \
--site-name="Tallpine Hiking Club" \
--admin-user="Tallpine Admin" \
--admin-username="tp_root" \
--admin-password="$TALLPINE_ADMIN_PASSWORD" \
--admin-email="admin@tallpine.example" \
--db-host="db" --db-name="tallpine" --db-user="tallpine" \
--db-pass="$TALLPINE_DB_PASSWORD" --db-prefix="tp_" \
--public-folder="public"
On an existing site, use the console command registered by the core:
php cli/joomla.php site:create-public-folder --public-folder=/var/www/tallpine/public
Points to know about the command and the helper:
-
The command needs the PHP function
symlink(); it stops with an error when the function is disabled. Many shared hosts disable it, and Windows needs the privilege to create symbolic links. -
The helper refuses to continue when the destination already contains an
index.php. -
The helper creates symlinks for
media, for the Joomla update extraction script and for every directory configured in the Filesystem - Local plugin (imagesandfilesby default). A directory added to that plugin later is not linked automatically; add a symlink to the public folder yourself. -
Files are copied, not linked:
robots.txtand.htaccess(orhtaccess.txt) are hard copies, so later edits to the root.htaccessdo not propagate. Edit the copy in the public folder, or recreate the folder. -
The success message reminds you to adjust your server configuration to serve from the public folder. The command does not touch the web server.
Pointing the web server at the folder
Apache needs only the document root changed. The copied rewrite rules work as before:
<VirtualHost *:443>
ServerName tallpine.example
DocumentRoot /var/www/tallpine/public
<Directory /var/www/tallpine/public>
AllowOverride All
Require all granted
</Directory>
# SSLEngine and certificate directives omitted
</VirtualHost>
Nginx does not read .htaccess, so the rewrite is written into the server block. The front controllers are the files in the
public folder, and the API is routed to api/index.php:
server {
listen 443 ssl;
server_name tallpine.example;
root /var/www/tallpine/public;
index index.php;
location /api/ {
try_files $uri $uri/ /api/index.php?$args;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.ht { deny all; }
}
The root must be the public folder and not the code tree. When SEF URLs and the API do not work on Nginx, the cause is
usually a missing /api/ location. Details about HTTPS, headers and PHP-FPM are in
Web Server, Reverse Proxy and HTTPS.
Pitfalls and security notes
-
Do not serve the code tree. If the virtual host still points at the old root after running the command, the site works and the intended protection is silently absent. Request
/configuration.phpand/libraries/from outside to confirm: the first must not be served at all and the second must be a 404. -
New directories are not linked. A new top-level static directory in the code tree (a downloads folder, for instance) is invisible to the browser until you add a symlink to it.
-
Updates and the public folder. The Joomla update extraction script is symlinked into the public folder so that the updater can still call it. If you recreate the folder, make sure that link exists, otherwise updates (including Automated Core Updates) fail at the extraction step.
-
Deployments. With atomic releases (a
currentsymlink that moves between release directories), prefer an absolute public folder pointing at the stable path, or generate the folder per release so that relative paths stay consistent. -
Hosts that force the document root. Shared hosting often fixes the document root to a directory such as
public_html. The public folder then needs a host that allows the document root to be configured, or the code tree can be placed abovepublic_htmland the generated files adapted by hand. -
Backups. Back up the code tree, the database and the real
images,filesandmediadirectories, not just the public folder, which contains mostly links. See Backups and Recovery.
htaccess.txt and .htaccess
Joomla ships htaccess.txt and does not ship an active .htaccess, because a file with unsupported directives can make
a site fail with a server error on some hosts. To use it on Apache, rename (or copy) it in the site root:
cd /var/www/tallpine # or the public folder when one is used
cp htaccess.txt .htaccess
The file does the following in Joomla 6.2:
-
switches off directory listings (
Options -Indexes) and enablesOptions +FollowSymlinks, which mod_rewrite needs; the comment in the file tells you to comment that line out if the host rejects it -
sends
X-Content-Type-Options: nosniffand disables inline JavaScript in directly opened SVG files, whenmod_headersis available -
contains optional cross-origin policy headers, commented out
-
blocks requests with suspicious query strings (base64 injection attempts,
<script>tags, attempts to setGLOBALSor_REQUEST) -
passes the
Authorizationheader to PHP, needed by the Web Services API token authentication -
rewrites
/api/requests that are not real files toapi/index.php, and any other request that is not a real file or directory toindex.php -
serves pre-compressed
.css.gzand.js.gzfiles when present
If the site looks broken after enabling the file with errors such as ERR_CONTENT_DECODING_FAILED, the host is already
compressing assets; comment out the compression block. On OpenLiteSpeed, restart the server after each change. When the
site shows a 500 error right after renaming, comment out Options +FollowSymlinks and reload. Nginx and IIS ignore the
file; their equivalents are the server block above and the IIS URL Rewrite rules. A detailed discussion of the
file and of configuration.php is in configuration.php and .htaccess.
Enabling SEF URLs
Out of the box Joomla builds URLs of the form index.php/trail-reports. Two switches in System → Global Configuration →
Site (the SEO Settings group) change that:
-
Search Engine Friendly URLs: Yes, which produces readable paths instead of
index.php?option=...query strings -
Use URL Rewriting: Yes, which removes
index.phpfrom the path; this requires.htaccesson Apache (or the equivalent on other servers) -
Add Suffix to URL is optional; set to Yes it appends
.htmlto page URLs
Order matters: rename htaccess.txt first, then enable Use URL Rewriting. With the switch on and no rewrite rules, every
page except the home page returns a 404. The same results can be set from the command line, which is useful in a scripted
installation:
php cli/joomla.php config:set sef=true sef_rewrite=true sef_suffix=false
Test with a menu item URL and with the API (/api/index.php/v1/content/articles and /api/v1/content/articles should both
respond, even if with an authentication error). Redirects, aliases and structured data are in
SEO, SEF URLs, Redirects and Schema.org. Older advice to fill in
meta keywords or to count keyword density is not part of current practice.
First login and post-installation
Logging in
Open https://tallpine.example/administrator/ and sign in with the Super User created in step 2. The administrator uses
the Atum template. After logging in, take the following steps before building anything:
-
Open System → Global Configuration and check the site name, the default access level, the Session Lifetime and the mail settings (set Mailer, From Email and From Name; send a test mail). Joomla stores the mail settings in
configuration.php. -
Set the Site Offline option when the site is not ready for visitors, or leave it online on a staging host that is protected by HTTP authentication.
-
Add multi-factor authentication to the Super User account (Joomla has had MFA in core since 4.2, which replaced the older two-factor authentication; passkeys are available too).
-
Review the API authentication plugins. On fresh 6.2 installs the API Authentication - Token plugin is enabled and API Authentication - Basic is disabled; leave Basic disabled.
-
Confirm that the caching, error reporting (Default or None in production) and debug system settings are appropriate for the environment.
Global Configuration is described screen by screen in Global Configuration.
Post-installation messages
The Post-installation Messages component (com_postinstall) shows messages for Joomla and its extensions after an
installation or an upgrade. Its title for the main page is Post-installation Messages for followed by the extension it
filters, and the buttons include Hide all Messages and Reset Messages. The messages are an inbox, not errors: they
announce new features, recommend options (for example enabling MFA, reviewing the new default behaviour of a plugin or
confirming that the update system works) and can be dismissed one by one. Read them once, act on the ones that apply to
your site, and hide the rest.
The same inbox shows messages again after an update that adds new ones. When a message refers to a plugin or a system check, the underlying state is described in the System Information page; see System Information, Maintenance and Troubleshooting.
What to check next
-
The Joomla Update component shows whether the installed version is current and displays the Automated Core Updates state.
-
System → Information lists PHP, database and directory permissions; the Directory Permissions tab should show the writable folders.
-
Create a second Super User or an Administrator for the people who will manage content, then use Groups and Access Levels (see Users, Groups, Access Levels and ACL).
-
Configure backups before any content is created; Joomla has no backup feature in core, so use a database dump plus a copy of the files or a third-party extension, as discussed in Backups and Recovery.
Common installation errors
| Symptom | Likely cause and fix |
|---|---|
The installer shows a page about an unsupported PHP version |
The host runs PHP below 8.3. Change the PHP version in the hosting panel or the container image |
A blank page or "Could not connect to database" |
Wrong host, user, password or database name; the user lacks privileges; a firewall or the socket path is wrong |
The installer starts again after finishing |
|
404 on every page but the home page |
Use URL Rewriting is on but |
500 error after copying |
A directive is rejected by the host; comment out |
The API returns 404 or 401 although the token is correct |
|
Public folder: images or CSS do not load |
A symlink is missing ( |
The command |
|
Site opens but |
The installer could not delete it; remove the directory manually |
Version notes
-
Joomla 4.0 removed support for Microsoft SQL Server; a migration between MySQL and PostgreSQL is not supported, and downgrades are not supported either.
-
Joomla 5.0 added the public folder (
PublicFolderGeneratorHelper,site:create-public-folderand the installer option). -
Joomla 5.1 introduced TUF-verified core updates; 5.4 and 6.0 added Automated Core Updates with an opt-out in the installer.
-
Joomla 6.0 raised the minimum PHP version to 8.3.
-
On fresh 6.2 installations the API token plugin is enabled and the Basic Auth plugin is disabled.