Deployment
A MARS server is one core (Server.Ignition.pas plus your resource units) that you can host in several ways. The MARSTemplate and MARSTemplateDCS templates (and the projects MARSCmd creates from them) contain a ready project for each host.
| Host | Project in the template | Typical use |
|---|---|---|
| Console | ...ServerConsoleApplication | development, quick tests |
| VCL / FMX application | ...ServerApplication, ...ServerFMXApplication | development, desktop tools |
| Windows service | ...ServerService | production on Windows |
| Linux daemon | ...ServerDaemon (...ServerDCSDaemon) | production on Linux, Docker |
| ISAPI (IIS) | ...ServerISAPI | inside IIS |
| Apache module | ...ServerApacheModule | inside Apache httpd |
| FastCGI | ...ServerFCGI | behind nginx |
The self-hosted flavors (console, GUI, service, daemon) run their own HTTP server: Indy (TMARShttpServerIndy, MARSTemplate) or Delphi Cross Socket (TMARShttpServerDCS, MARSTemplateDCS). The ISAPI, Apache and FastCGI flavors go through WebBroker and the web server does the HTTP part.
Files to deploy
Next to the executable:
- the
.inifiles:Server.iniwith the settings shared by all the flavors and<executable name>.inithat includes it; - the certificate and private key, if the server terminates HTTPS itself (HTTPS);
- the OpenSSL libraries for HTTPS on Windows (
libssl-3-x64.dll,libcrypto-3-x64.dllfor DCS); - the static files, if any (i.e. Swagger UI, see below).
The .ini files are found next to the executable whatever the working directory, so services and daemons read them too.
Static files and paths
The templates serve Swagger UI from the www folder of MARS with a relative Windows path (RootFolder('{bin}\..\..\..\www\swagger-ui-3.52.5-dist', True)), which works on the development machine only. For a deployment copy the folder next to the executable and use a portable path, for example:
[Path('www/{*}'), RootFolder('{bin}' + PathDelim + 'www', True), MetaVisible(False)]{bin} is the folder of the executable; PathDelim makes the same code work on Windows and Linux.
Windows service
The ...ServerService project is a standard VCL service. Its name and display name come from the configuration (ServiceName, ServiceDisplayName in its .ini file), so copies of the executable in different folders, each with its own .ini files, can run side by side as different services.
REM from an administrator prompt
MyProjectServerService.exe /install
sc start MyProjectService
REM remove it
sc stop MyProjectService
MyProjectServerService.exe /uninstallLinux with systemd
Build the ...ServerDaemon project for the Linux64 platform (RAD Studio with the Linux SDK and PAServer), then copy the binary and the .ini files to the server, i.e. to /opt/myproject.
The daemon runs in two ways:
./MyProjectServerDaemondetaches from the terminal (classic daemon: fork, new session) and logs toMyProjectServerDaemon.lognext to the binary;./MyProjectServerDaemon --foreground(or-f) stays in the current process and logs to standard output. This is what systemd and Docker expect.
Both stop on SIGTERM (and SIGINT in foreground). The foreground mode is available after MARS 1.8.1; with older versions use Type=forking and no --foreground. A systemd unit, /etc/systemd/system/myproject.service:
[Unit]
Description=MyProject REST server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myproject
WorkingDirectory=/opt/myproject
ExecStart=/opt/myproject/MyProjectServerDaemon --foreground
Restart=on-failure
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now myproject
journalctl -u myproject -fDocker
Run the daemon in foreground as the main process of the container. A Dockerfile next to the Linux build output (bin):
FROM ubuntu:24.04
# OpenSSL is needed only if the server terminates HTTPS itself (DCS)
RUN apt-get update \
&& apt-get install -y --no-install-recommends openssl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY bin/MyProjectServerDCSDaemon bin/*.ini /app/
COPY bin/www /app/www
EXPOSE 8080
CMD ["./MyProjectServerDCSDaemon", "--foreground"]docker build -t myproject .
docker run -d --name myproject -p 8080:8080 myproject
docker logs -f myprojectdocker stop sends SIGTERM and the server stops cleanly. Use a base image close to the Linux SDK you build with (the RAD Studio Linux SDKs are Ubuntu based); ldd ./MyProjectServerDCSDaemon lists the libraries the binary needs. Keep secrets such as JWT.Secret out of the image: mount the .ini file holding them (-v /etc/myproject/Server.ini:/app/Server.ini:ro).
Behind a reverse proxy
The most common production setup: the MARS server listens on plain HTTP on the local machine (or in the container network) and a reverse proxy terminates HTTPS, with certificates renewed automatically (i.e. Let's Encrypt).
nginx:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
# server-sent events: no buffering, long reads
proxy_buffering off;
proxy_read_timeout 1h;
}
}The X-Forwarded-* headers matter: the MCP OAuth metadata uses them to publish the public https address. On Windows the same works with IIS and Application Request Routing (ARR), or with Caddy (reverse_proxy 127.0.0.1:8080, certificates included).
If browsers call the API from another origin, enable the CORS.* parameters.
HTTPS without a proxy
Both self-hosted servers can terminate HTTPS: PortSSL plus the certificate and key, see HTTPS.
- DCS loads a current OpenSSL (3.x) at run time. Use the certificate chain (
fullchain.pem) as certificate file. - Indy requires OpenSSL 1.0.2 (
libeay32.dll,ssleay32.dll), out of support since 2019.Indy.SSL.Version=sslvTLSv1_2(the default) means TLS 1.2 only, and with OpenSSL 1.0.2 Indy negotiates RSA key exchange only (no ECDHE, so no forward secrecy), which recent browsers may refuse. With Indy, prefer a reverse proxy for public endpoints.
ISAPI, Apache, FastCGI
These flavors build a library or a FastCGI program that the web server loads; ports, HTTPS and the process lifetime are up to the web server, so Port, PortSSL and the SSL parameters do not apply.
IIS: deploy the
...ServerISAPIDLL in an application with the ISAPI handler enabled; the bitness of the DLL must match the application pool (32-bit pools need a Win32 build).Apache 2.4:
LoadModulethe...ServerApacheModulelibrary (.dllon Windows,.soon Linux) and map a location to its handler:apacheLoadModule myproject_module modules/mod_myproject.so <Location /rest> SetHandler mod_myproject-handler </Location>The module name is the one exported by the project (
exports GModuleData name 'myproject_module').FastCGI: run
...ServerFCGIand point nginx (fastcgi_pass) or Apache to it.
Production checklist
- Release build, with a strong
JWT.SecretinServer.ini(MARSCmd generates one per project; a RELEASE build refuses to issue tokens without it). See Authentication. - HTTPS: a reverse proxy, or DCS directly (see above).
- Indy:
Indy.KeepAlive=true(theMARSTemplatedefault since 1.8.1) andThreadPoolSizeat least as large as the expected concurrent connections: each open connection holds a thread and the pool size is also the connection limit. - CORS parameters if browsers call the API from other origins.
- Logging: the JSON logger for Grafana/Loki, or the daemon output collected by journald or Docker.
- Static files copied next to the executable with a portable
RootFolder(see above). - Many cores, many concurrent requests: the default Delphi memory manager serializes allocations from many threads; a multi-threaded memory manager (i.e. FastMM5) lets the server use all the cores.
