Skip to main content

Overview

Apache module deployment allows you to run Horse applications as native Apache modules. This provides tight integration with Apache’s infrastructure, including its process management, logging, security features, and extensive module ecosystem.
Apache deployment requires the HORSE_APACHE conditional define and compiles to a DLL (Windows) or SO (Linux) library instead of an executable.

When to Use Apache Deployment

  • Enterprise Hosting: Integration with existing Apache infrastructure
  • Shared Hosting: Multiple applications on a single Apache instance
  • Load Balancing: Leverage Apache’s built-in load balancing
  • Security: Use Apache’s authentication and authorization modules
  • Static + Dynamic: Serve static content with Apache, dynamic with Horse
  • Reverse Proxy: Apache handles SSL termination and proxying

Required Conditional Define

You must add HORSE_APACHE to your project’s conditional defines.
1

Open Project Options

Go to Project → Options → Delphi Compiler → Compiling
2

Add Conditional Define

Add: HORSE_APACHE
3

Change Target to Library

Ensure your project is a library (not program)
4

Rebuild Project

Clean and rebuild your project completely

Complete Apache Module Example

library Apache;

{$R *.res}

(*
 httpd.conf entries:
 LoadModule apache_horse_module modules/Apache.dll
 <Location /apache_horse>
    SetHandler apache_horse_module-handle
 </Location>
 To use the feature:
 http://localhost/apache_horse/ping
 These entries assume that the output directory for this project is the apache/modules directory.
 httpd.conf entries should be different if the project is changed in these ways:
   1. The TApacheModuleData variable name is changed.
   2. The project is renamed.
   3. The output directory is not the apache/modules directory.
   4. The dynamic library extension depends on a platform. Use .dll on Windows and .so on Linux.
*)

// Declare exported variable so that Apache can access this module.

uses Horse, Web.HTTPD24Impl;

var
  ApacheModuleData: TApacheModuleData;

exports
  ApacheModuleData name 'apache_horse_module';

begin
  // Need to set "HORSE_APACHE" compilation directive

  THorse.DefaultModule := @ApacheModuleData;
  THorse.HandlerName := 'apache_horse_module-handle';

  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen;
end.

Apache Configuration

Windows Configuration

1

Copy Module to Apache Directory

Copy your compiled Apache.dll to the Apache modules directory:
copy Apache.dll "C:\Apache24\modules\"
2

Edit httpd.conf

Add the following to your httpd.conf file:
# Load the Horse module
LoadModule apache_horse_module modules/Apache.dll

# Configure location
<Location /apache_horse>
    SetHandler apache_horse_module-handle
</Location>
3

Restart Apache

httpd.exe -k restart
4

Test the Module

Navigate to: http://localhost/apache_horse/ping

Linux Configuration

1

Copy Module to Apache Directory

sudo cp Apache.so /usr/lib/apache2/modules/
sudo chmod 755 /usr/lib/apache2/modules/Apache.so
2

Create Module Configuration

Create /etc/apache2/mods-available/horse.load:
LoadModule apache_horse_module /usr/lib/apache2/modules/Apache.so
Create /etc/apache2/mods-available/horse.conf:
<Location /apache_horse>
    SetHandler apache_horse_module-handle
</Location>
3

Enable Module

sudo a2enmod horse
sudo systemctl restart apache2
4

Test the Module

curl http://localhost/apache_horse/ping

Advanced Configuration

Multiple Routes and Endpoints

library ApacheAPI;

uses
  Horse,
  Web.HTTPD24Impl,
  System.JSON,
  System.SysUtils;

var
  ApacheModuleData: TApacheModuleData;

exports
  ApacheModuleData name 'horse_api_module';

begin
  THorse.DefaultModule := @ApacheModuleData;
  THorse.HandlerName := 'horse_api_module-handle';

  // Health check
  THorse.Get('/health',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('{"status": "healthy"}');
    end);

  // RESTful API endpoints
  THorse.Get('/api/users',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('[{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]');
    end);

  THorse.Get('/api/users/:id',
    procedure(Req: THorseRequest; Res: THorseResponse)
    var
      UserId: string;
    begin
      UserId := Req.Params['id'];
      Res.Send(Format('{"id": %s, "name": "User %s"}', [UserId, UserId]));
    end);

  THorse.Post('/api/users',
    procedure(Req: THorseRequest; Res: THorseResponse)
    var
      Body: string;
    begin
      Body := Req.Body;
      Res.Status(201).Send('{"id": 3, "created": true}');
    end);

  // Static content fallback
  THorse.Get('/assets/*',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('Asset served by Apache');
    end);

  THorse.Listen;
end.

Apache Configuration with Virtual Hosts

# Load the module
LoadModule horse_api_module modules/ApacheAPI.dll

<VirtualHost *:80>
    ServerName api.example.com
    DocumentRoot "C:/www/api"
    
    # Serve static files with Apache
    <Directory "C:/www/api/static">
        Require all granted
    </Directory>
    
    # Route API requests to Horse module
    <Location /api>
        SetHandler horse_api_module-handle
    </Location>
    
    # Health check endpoint
    <Location /health>
        SetHandler horse_api_module-handle
    </Location>
    
    ErrorLog "logs/api-error.log"
    CustomLog "logs/api-access.log" common
</VirtualHost>

SSL/TLS Configuration

<VirtualHost *:443>
    ServerName api.example.com
    
    SSLEngine on
    SSLCertificateFile "conf/ssl/server.crt"
    SSLCertificateKeyFile "conf/ssl/server.key"
    SSLCertificateChainFile "conf/ssl/ca-bundle.crt"
    
    # Modern SSL configuration
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite HIGH:!aNULL:!MD5
    SSLHonorCipherOrder on
    
    <Location /api>
        SetHandler horse_api_module-handle
    </Location>
</VirtualHost>

Module Configuration Options

Setting Handler Name

THorse.HandlerName := 'my_custom_handler';
Corresponding Apache config:
<Location /myapp>
    SetHandler my_custom_handler
</Location>

Max Connections

THorse.MaxConnections := 100;

Module-Specific Settings

begin
  // Configure module
  THorse.DefaultModule := @ApacheModuleData;
  THorse.HandlerName := 'apache_horse_module-handle';
  THorse.MaxConnections := 200;
  
  // Configure routes
  ConfigureRoutes;
  
  // Start listening
  THorse.Listen(
    procedure
    begin
      // Initialization callback
      // Note: Don't use console output in Apache modules
    end);
end;

Reverse Proxy Alternative

Instead of using the Apache module, you can also run Horse as a console application and use Apache as a reverse proxy.
# Enable required modules
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<VirtualHost *:80>
    ServerName api.example.com
    
    # Proxy to Horse console application
    ProxyPreserveHost On
    ProxyPass /api http://localhost:9000/api
    ProxyPassReverse /api http://localhost:9000/api
    
    # WebSocket support (if needed)
    ProxyPass /ws ws://localhost:9000/ws
    ProxyPassReverse /ws ws://localhost:9000/ws
</VirtualHost>

Performance Optimization

Apache MPM Configuration

# For Windows (MPM WinNT)
<IfModule mpm_winnt_module>
    ThreadsPerChild 250
    MaxConnectionsPerChild 0
</IfModule>

# For Linux (MPM Worker)
<IfModule mpm_worker_module>
    StartServers 3
    MinSpareThreads 75
    MaxSpareThreads 250
    ThreadsPerChild 25
    MaxRequestWorkers 400
    MaxConnectionsPerChild 0
</IfModule>

Caching

<Location /api>
    SetHandler horse_api_module-handle
    
    # Cache static responses
    <If "%{REQUEST_URI} =~ /static/">
        Header set Cache-Control "max-age=86400, public"
    </If>
</Location>

Troubleshooting

Module Fails to Load

Common issues:
  • Missing HORSE_APACHE conditional define
  • Incorrect export declaration
  • Missing dependencies (RTL packages)
  • Mismatched Apache version (requires Apache 2.4)
# Check Apache error log
tail -f /var/log/apache2/error.log

# Test configuration
apachectl configtest

# Load module manually
apachectl -M | grep horse

Handler Not Found

Verify handler name matches:
// In code
THorse.HandlerName := 'apache_horse_module-handle';
# In httpd.conf
SetHandler apache_horse_module-handle

Memory Leaks

// Enable leak reporting in development
{$IFDEF DEBUG}
ReportMemoryLeaksOnShutdown := True;
{$ENDIF}

Permission Issues (Linux)

# Ensure correct permissions
sudo chown root:root /usr/lib/apache2/modules/Apache.so
sudo chmod 755 /usr/lib/apache2/modules/Apache.so

# Check SELinux (if enabled)
sudo setenforce 0  # Temporarily disable for testing

Platform-Specific Considerations

Windows

  • Use .dll extension
  • Place in Apache24\modules\
  • May require Visual C++ Redistributable
  • Test with httpd.exe -t

Linux

  • Use .so extension
  • Place in /usr/lib/apache2/modules/
  • Ensure proper file permissions (755)
  • Use apache2ctl configtest

Deployment Checklist

1

Compile Module

HORSE_APACHE conditional define set
✅ Built as library (not program)
✅ Release configuration
✅ Correct target platform
2

Install Module

✅ Copied to Apache modules directory
✅ Correct file permissions
✅ Correct file extension (.dll/.so)
3

Configure Apache

✅ LoadModule directive added
✅ Handler configured
✅ Location/Directory settings
✅ Configuration tested
4

Test Deployment

✅ Apache starts successfully
✅ Module loads without errors
✅ Endpoints respond correctly
✅ Error handling works

Next Steps

ISAPI Deployment

Deploy with IIS using ISAPI

CGI Deployment

Standard CGI deployment

Build docs developers (and LLMs) love