Skip to content

Windows Service Deployment

Run your Kittox application as a Windows Service for unattended, production-ready operation. The same executable used for Desktop GUI automatically detects service mode.

When to use

  • Production on Windows Server
  • Unattended operation with automatic startup
  • Applications that must survive user logoff
  • Behind a reverse proxy (Apache, nginx, or IIS) for HTTPS, security, and load balancing
  • When you need to restart individual applications without restarting the web server

Advantages over native modules (ISAPI/Apache)

Windows Service + ProxyISAPI / Apache module
Restart individual appsYes (via Services panel or net stop/net start)No (must restart IIS/Apache)
DLL lockingNo lock — the .exe runs independentlyDLL locked by the web server process
YAML reloadRestart the service to reload metadataRestart the entire web server
DebuggingRun as Desktop GUI, attach debuggerComplex (attach to IIS/Apache worker)
Multiple instancesEach app is a separate service on its own portAll apps share the web server process
Web server dependencyAny reverse proxy (Apache, nginx, IIS, Caddy...)Tied to a specific web server

The .dpr file

The same .dpr used for the Desktop GUI:

pascal
program MyApp;
uses
  Kitto.Vcl.Start,
  Controllers, Rules, UseKitto;
begin
  TKStart.Start;
end.

TKStart.Start auto-detects service mode: if the process was started by the Windows Service Control Manager (SCM), it runs as a service; otherwise it starts the desktop GUI.

Service configuration (Config.yaml)

yaml
AppName: MyAppX
AppPath: /myappx

Server:
  Port: 8080
  BindAddress: ''
  ThreadPoolSize: 20

Service:
  # Log server events to Windows Event Viewer
  LogToEventViewer: True

Log:
  Level: detailed
  TextFile:
    FileName: %APP_PATH%.log
    IsEnabled: True

Port assignment

Each application needs its own unique port. The examples use:

  • HelloKittoX: 3621
  • TaskittoX: 3622
  • KEmployeeX: 3623

Installing the service

Each example application includes ready-to-use batch scripts in the Home\ directory:

InstallService.bat:

batch
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
    echo ERROR: This script must be run as Administrator.
    echo Right-click and select "Run as administrator".
    pause
    exit /b 1
)
echo Installing MyAppX service...
"%~dp0MyApp.exe" -install
echo Starting MyAppX service...
net start MyAppX
echo.
echo Service installed and started.
pause

UninstallService.bat:

batch
@echo off
net session >nul 2>&1
if %errorlevel% neq 0 (
    echo ERROR: This script must be run as Administrator.
    echo Right-click and select "Run as administrator".
    pause
    exit /b 1
)
echo Stopping MyAppX service...
net stop MyAppX 2>nul
echo Uninstalling MyAppX service...
"%~dp0MyApp.exe" -uninstall
echo.
echo Service stopped and uninstalled.
pause

Right-click the .bat file and select Run as administrator.

Manual installation

Open an elevated command prompt (Run as Administrator):

batch
:: Install the service
MyApp.exe -install

:: Start the service
net start MyAppX

:: Verify it's running
sc query MyAppX

The service name is the AppName value from Config.yaml. The service is installed with Automatic startup type.

Uninstalling manually

batch
:: Stop the service
net stop MyAppX

:: Uninstall
MyApp.exe -uninstall

Running under a specific account

By default, the service runs as Local System. For database access with Windows Authentication, change the service account:

  1. Open Services (services.msc)
  2. Find your service, right-click > Properties
  3. Go to the Log On tab
  4. Select This account and enter a domain user with database access
  5. Click OK and restart the service

Reverse proxy configuration

In production, place the service behind a reverse proxy for HTTPS termination, security filtering, and a clean URL structure. The service runs on localhost:port and the proxy forwards external requests to it.

Install nginx and configure conf/nginx.conf:

nginx
http {
    server {
        listen 80;
        server_name  localhost;

        # --- HelloKittoX (port 3621) ---
        location /hellokittox/ {
            proxy_pass http://127.0.0.1:3621/hellokittox/;
            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;
        }
        location = /hellokittox {
            return 301 /hellokittox/;
        }

        # --- TaskittoX (port 3622) ---
        location /taskittox/ {
            proxy_pass http://127.0.0.1:3622/taskittox/;
            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;
        }
        location = /taskittox {
            return 301 /taskittox/;
        }
    }
}

Each application needs two location blocks: one for the trailing-slash redirect and one for the actual proxy.

nginx commands:

batch
:: Test configuration
nginx.exe -t

:: Start
nginx.exe

:: Reload configuration (no downtime)
nginx.exe -s reload

:: Stop
nginx.exe -s stop

HTTPS with nginx:

nginx
server {
    listen 443 ssl;
    server_name  myserver.example.com;

    ssl_certificate      conf/ssl/server.crt;
    ssl_certificate_key  conf/ssl/server.key;

    location /hellokittox/ {
        proxy_pass http://127.0.0.1:3621/hellokittox/;
        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;
    }
    location = /hellokittox {
        return 301 /hellokittox/;
    }
}

Apache

Enable mod_proxy and mod_proxy_http in httpd.conf:

apache
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Then add the proxy rules:

apache
<IfModule proxy_http_module>
    # HelloKittoX (port 3621)
    ProxyPass "/hellokittox" "http://localhost:3621/hellokittox"
    ProxyPassReverse "/hellokittox" "http://localhost:3621/hellokittox"

    # TaskittoX (port 3622)
    ProxyPass "/taskittox" "http://localhost:3622/taskittox"
    ProxyPassReverse "/taskittox" "http://localhost:3622/taskittox"

    # KEmployeeX (port 3623)
    ProxyPass "/kemployeex" "http://localhost:3623/kemployeex"
    ProxyPassReverse "/kemployeex" "http://localhost:3623/kemployeex"
</IfModule>

HTTPS: add the same ProxyPass directives inside your <VirtualHost *:443> block.

Apache vs nginx

Apache requires separate modules (mod_proxy, mod_proxy_http) and more verbose configuration. nginx has reverse proxy built-in and the configuration is more compact. Both work equally well.

IIS (Application Request Routing)

  1. Install Application Request Routing (ARR) and URL Rewrite modules from the IIS downloads page
  2. Open IIS Manager > server node > Application Request Routing Cache > Server Proxy Settings
  3. Check Enable proxy and click Apply
  4. Create a URL Rewrite inbound rule:
    • Pattern: ^hellokittox/(.*)
    • Action type: Rewrite
    • Rewrite URL: http://localhost:3621/hellokittox/{R:1}

Repeat for each application.

Monitoring

  • Services panel: services.msc shows status, allows start/stop/restart
  • Event Viewer: if LogToEventViewer: True, server start/stop and errors appear in the Application log
  • Log file: %APP_PATH%.log next to the executable (if Log/TextFile/IsEnabled: True)
  • Browser: navigate to http://localhost/myappx/ (via proxy) or http://localhost:8080/myappx/ (direct)
  • Service status: sc query MyAppX

Troubleshooting

IssueSolution
"Run as administrator" errorThe batch scripts check for admin privileges. Right-click > Run as administrator
Service fails to startCheck the log file next to the .exe. Common cause: port already in use
502 Bad Gateway (nginx/Apache)The service is not running or listening on the wrong port. Check Server/Port in Config.yaml
404 on proxyAppPath in Config.yaml must match the proxy path exactly
Database connection failsChange the service account (Log On tab) to a user with database access
Sessions lost on restartExpected behavior — sessions are in-memory. Users will see the "Session lost" dialog and can re-login

See also

Released under Apache License, Version 2.0.