Horilla is an open source human resource management platform built with Django, and AlmaLinux is a strong server choice for running it in a stable, enterprise-style environment. A typical installation requires Python, PostgreSQL, system build tools, a virtual environment, and a production web stack such as Gunicorn and Nginx. The following guide explains how an administrator can install Horilla on AlmaLinux, prepare its dependencies, configure services, and resolve common issues that appear during deployment.
TLDR: Horilla can be installed on AlmaLinux by preparing Python, PostgreSQL, development libraries, and a dedicated application user. The administrator should clone the Horilla source code, create a Python virtual environment, install dependencies, configure environment variables, run database migrations, and serve the application with Gunicorn and Nginx. Most installation problems are caused by missing system packages, database connection errors, incorrect file permissions, or SELinux restrictions.
Understanding the Recommended Setup
A production-ready Horilla deployment on AlmaLinux usually includes several layers. PostgreSQL stores the application data, Python runs the Django application, Gunicorn acts as the application server, and Nginx handles public web traffic, static files, and reverse proxying. This arrangement is more reliable than running Django’s development server directly.
Before installation begins, the server should have a clean AlmaLinux 8 or 9 installation, a non-root user with sudo privileges, internet access, and a fully qualified domain name if HTTPS will be configured. The administrator should also confirm the Horilla version requirements from the official project repository, especially the supported Python version.

Step 1: Update AlmaLinux and Install Base Packages
The first step is to update the operating system and install common utilities. Keeping packages current reduces compatibility issues and security risks.
sudo dnf update -y
sudo dnf install -y git curl wget vim tar gcc gcc-c++ make
Many Python packages require compilation during installation. For that reason, development tools and header files are important. Missing compiler packages often cause pip install failures with errors related to building wheels.
Step 2: Install Python and Development Headers
Horilla is a Django application, so Python must be installed with the correct version. On AlmaLinux 9, Python 3.11 is commonly available through the default repositories or AppStream modules.
sudo dnf install -y python3.11 python3.11-devel python3.11-pip
If the server uses AlmaLinux 8, the administrator may need to enable additional repositories or use an approved Python source depending on the required version. After installation, the version can be checked with:
python3.11 --version
The administrator should avoid mixing system Python packages with application packages. A virtual environment keeps Horilla dependencies isolated and prevents conflicts with operating system tools.
Step 3: Install PostgreSQL
Horilla typically uses PostgreSQL for persistent data storage. PostgreSQL can be installed from AlmaLinux repositories, although some administrators prefer the official PostgreSQL repository for newer versions.
sudo dnf install -y postgresql-server postgresql-contrib postgresql-devel
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
Next, a database and user should be created for Horilla. The administrator can switch to the PostgreSQL system account and run the database shell:
sudo -iu postgres
psql
Inside PostgreSQL, create a user and database:
CREATE USER horilla_user WITH PASSWORD 'StrongDatabasePassword';
CREATE DATABASE horilla_db OWNER horilla_user;
ALTER ROLE horilla_user SET client_encoding TO 'utf8';
ALTER ROLE horilla_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE horilla_user SET timezone TO 'UTC';
\q
exit
The password should be replaced with a secure value. In production, credentials should never be reused or stored in public files.
Step 4: Create a Dedicated Horilla User
Running Horilla as a dedicated Linux user improves security and file ownership management. The application should not run as root.
sudo useradd --system --create-home --shell /bin/bash horilla
sudo mkdir -p /opt/horilla
sudo chown horilla:horilla /opt/horilla
The installation can then continue under the new account:
sudo -iu horilla
cd /opt/horilla
Step 5: Clone Horilla and Create a Virtual Environment
The administrator can clone the Horilla source code from the project repository. If a specific stable release is available, it is usually better to deploy that release rather than an active development branch.
git clone https://github.com/horilla-opensource/horilla.git .
python3.11 -m venv venv
source venv/bin/activate
pip install --upgrade pip setuptools wheel
After the virtual environment is active, Python packages can be installed:
pip install -r requirements.txt
If this step fails, the most likely causes are missing development headers, an unsupported Python version, or a missing PostgreSQL development package. The package postgresql-devel is especially important when Python database adapters need to compile.
Step 6: Configure Environment Variables
Horilla configuration may be stored in an environment file, a settings file, or variables loaded by the service manager, depending on the project version. The administrator should check the repository for an example file such as .env.example. A typical configuration includes the secret key, debug mode, allowed hosts, database name, database user, database password, host, and port.
cp .env.example .env
vim .env
Common values may look like this:
DEBUG=False
SECRET_KEY=replace_with_a_long_random_secret
ALLOWED_HOSTS=example.com,www.example.com,127.0.0.1
DB_NAME=horilla_db
DB_USER=horilla_user
DB_PASSWORD=StrongDatabasePassword
DB_HOST=127.0.0.1
DB_PORT=5432
The administrator should adapt these variables to match the actual Horilla settings format. Incorrect variable names can prevent Django from reading the configuration, so the project documentation should be treated as authoritative.
Step 7: Run Migrations, Create an Admin User, and Collect Static Files
Database migrations create the tables required by Horilla. From the application directory, with the virtual environment activated, the administrator can run:
python manage.py migrate
python manage.py createsuperuser
python manage.py collectstatic
If the application includes initial data commands or setup scripts, those should be executed according to the project documentation. After migrations complete, a quick test can be performed locally:
python manage.py runserver 127.0.0.1:8000
If the server responds locally, the core application stack is working. The development server should then be stopped because Gunicorn and Nginx are preferred for production.
Step 8: Configure Gunicorn as a Systemd Service
Gunicorn runs the Django application as a managed background service. If Gunicorn is not already installed through the requirements file, it can be installed manually inside the virtual environment:
pip install gunicorn
exit
Then the administrator can create a systemd service file:
sudo vim /etc/systemd/system/horilla.service
A basic service may look like this:
[Unit]
Description=Horilla Gunicorn Service
After=network.target postgresql.service
[Service]
User=horilla
Group=horilla
WorkingDirectory=/opt/horilla
EnvironmentFile=/opt/horilla/.env
ExecStart=/opt/horilla/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 horilla.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.target
The exact WSGI module may differ depending on the project layout. If horilla.wsgi:application is not correct, the administrator should inspect the directory containing wsgi.py and adjust the command.
sudo systemctl daemon-reload
sudo systemctl enable --now horilla
sudo systemctl status horilla
Step 9: Configure Nginx Reverse Proxy
Nginx receives public requests and forwards dynamic traffic to Gunicorn. It can also serve static and media files more efficiently than the Python application server.
sudo dnf install -y nginx
sudo systemctl enable --now nginx
Create a server block:
sudo vim /etc/nginx/conf.d/horilla.conf
server {
listen 80;
server_name example.com www.example.com;
location /static/ {
alias /opt/horilla/static/;
}
location /media/ {
alias /opt/horilla/media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
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;
}
}
After saving the file, Nginx should be tested and reloaded:
sudo nginx -t
sudo systemctl reload nginx
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
For HTTPS, the administrator can install Certbot and request a TLS certificate after DNS points to the server.
Troubleshooting Common Horilla Installation Problems
Python package installation fails: This usually indicates missing compilers or development libraries. The administrator should confirm that gcc, python3.11-devel, and postgresql-devel are installed. Running pip install –upgrade pip wheel setuptools also helps.
Database connection refused: PostgreSQL may not be running, the credentials may be wrong, or the host value may be incorrect. The administrator should check systemctl status postgresql, confirm the database user, and test with psql.
Gunicorn service fails to start: The most helpful command is:
sudo journalctl -u horilla -xe
The logs often reveal a missing environment variable, wrong WSGI path, permission issue, or module import error.
Nginx shows 502 Bad Gateway: This means Nginx cannot reach Gunicorn. The administrator should confirm that the Horilla service is running and listening on 127.0.0.1:8000. A mismatch between the Gunicorn bind address and Nginx proxy address is a common cause.
Static files do not load: The administrator should run collectstatic, confirm the Nginx alias path, and verify that Nginx can read the static directory. File permissions should allow traversal of parent directories.
SELinux blocks access: AlmaLinux often runs SELinux in enforcing mode. If Nginx cannot connect to Gunicorn, the administrator may need:
sudo setsebool -P httpd_can_network_connect 1
For file access problems, audit logs can be reviewed with ausearch or journalctl. SELinux should not be disabled casually; proper policies or contexts are safer.
Maintenance Tips
After installation, the administrator should create regular PostgreSQL backups, monitor disk usage, rotate logs, and test updates in a staging environment before applying them to production. The Horilla directory should be owned by the application user, while secrets should be readable only by trusted users. A routine update process may include pulling a tagged release, activating the virtual environment, installing updated requirements, running migrations, collecting static files, and restarting the service.
FAQ
-
Can Horilla run on AlmaLinux 9?
Yes. AlmaLinux 9 is a suitable platform when the required Python version, PostgreSQL, and build dependencies are installed. -
Is PostgreSQL required for Horilla?
PostgreSQL is the recommended database for a stable deployment. The administrator should follow the database requirements stated by the Horilla project. -
Should Horilla be run with Django’s development server?
No. The development server is useful for testing, but production deployments should use Gunicorn behind Nginx. -
What causes a 502 Bad Gateway error?
A 502 error usually means Nginx cannot communicate with Gunicorn. The administrator should check the Horilla service status, Gunicorn bind address, and Nginx proxy configuration. -
How can static file problems be fixed?
The administrator should run python manage.py collectstatic, verify the static path in Nginx, and check file permissions. -
Is SELinux compatible with Horilla?
Yes. SELinux can remain enabled, but Nginx network access and file contexts may need adjustment depending on the deployment layout. -
How should Horilla be updated?
Updates should be tested first, then applied by updating the code, reinstalling dependencies, running migrations, collecting static files, and restarting Gunicorn.
