Knowledge Base

SecurePACS Vault Gateway User Manual

The SecurePACS Vault Gateway is a high-performance DICOM-to-Web gateway. It listens for incoming DICOM studies via DIMSE, stores them locally, and securely uploads them to SecurePACS with end-to-end e

Backend Service v1.3.0 Updated May 16, 2026

SecurePACS Vault Gateway User Manual

The SecurePACS Vault Gateway is a high-performance DICOM-to-Web gateway. It listens for incoming DICOM studies via DIMSE, stores them locally, and securely uploads them to SecurePACS with end-to-end encryption.

Secure by Design

All studies are encrypted locally before being transmitted to SecurePACS. Sensitive DICOM tags are protected using public-key cryptography (P-521 ECDH + AES-CBC-256), ensuring that only authorized recipients can view the data.

Quick Start

Get the gateway running in 4 easy steps.

1. Install

Download the binaries or build from source using .NET 8.

2. Setup Wizard

Run the app. The interactive wizard guides you through mandatory settings and saves them to appsettings.Local.json.

3. Run

Start as a Windows Service or systemd daemon on Linux.

4. Dashboard

Open http://localhost:11113 to monitor studies, logs, and configuration in real-time.

Interactive Setup Wizard

If Gateway:SecurePacs:PublicKeyId is not configured, the gateway enters Setup Mode and serves a browser-based setup wizard at http://127.0.0.1:11113/setup.html. The wizard guides you through mandatory settings and saves them to appsettings.Local.json, then automatically restarts into normal mode. When deploying as a headless service, pre-populate appsettings.Local.json or set Gateway__SecurePacs__PublicKeyId via environment variable before first start. See the Setup Mode section for details.

Installation

Deploying the gateway as a background service.

Build

dotnet publish -c Release -r win-x64 --self-contained false -o ./publish

Adjust -r for your platform: win-x64, win-arm64, linux-x64, linux-arm64.

Windows Service

The gateway can be installed using PowerShell (Run as Administrator):

New-Service -Name "SecurePACSVaultGateway" `
  -BinaryPathName "C:\Path\To\Gateway\SecurePACS.Vault.Gateway.exe" `
  -DisplayName "SecurePACS Vault Gateway" `
  -Description "Receives DICOM studies and uploads them to SecurePACS." `
  -StartupType Automatic

Start-Service "SecurePACSVaultGateway"

Linux (systemd)

Create /etc/systemd/system/SecurePACS-gateway.service:

[Unit]
Description=SecurePACS Vault Gateway
After=network.target

[Service]
Type=notify
ExecStart=/path/to/gateway/SecurePACS.Vault.Gateway
WorkingDirectory=/path/to/gateway
User=gatewayuser
Group=gatewaygroup
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Then run: sudo systemctl enable --now SecurePACS-gateway

Configuration Layering

Settings are resolved in this order (later overrides earlier):
1. appsettings.json — ships with defaults; do not edit directly.
2. appsettings.Local.json — written by the wizard and dashboard; place your overrides here.
3. Environment variables — use Gateway__Key__SubKey=value (double underscores).

Setup Mode

First-run web wizard for mandatory configuration.

When the gateway starts without a configured Gateway:SecurePacs:PublicKeyId it enters Setup Mode. In Setup Mode the gateway starts a minimal web server and redirects all requests to /setup.html — a guided browser wizard that collects the required settings.

What the Wizard Collects

  • Gateway Instance ID
  • SecurePACS Public Key ID and Base URL
  • DICOM AE Title and listener port
  • Storage and database paths
  • Optional admin password (hashed before saving)

How It Works

  1. The wizard calls GET /api/setup/status to confirm it is in Setup Mode.
  2. A folder-browser widget calls POST /api/setup/folders/list (loopback only) to help select local paths.
  3. On completion, the wizard calls POST /api/setup/save which writes appsettings.Local.json and restarts the gateway into normal operational mode after a 2-second delay.

Setup API is Loopback-Only

All /api/setup/* endpoints are restricted to 127.0.0.1 / ::1. They are not accessible from remote machines. To re-run the wizard after initial configuration, use POST /system/config/reset from loopback (or delete appsettings.Local.json manually) and restart.

Configuration

All settings live under the Gateway: key in appsettings.json / appsettings.Local.json.

General & Identity
KeyDefaultDescription
Gateway:InstanceIdsecurepacs-gateway-01Unique name for this gateway instance. Shown in the startup banner and status responses.
DICOM Listener (DIMSE)
KeyDefaultDescription
Gateway:Dicom:AeTitleSECUREPACS_GWApplication Entity Title advertised to modalities.
Gateway:Dicom:MaxAssociations16Maximum concurrent DICOM associations (0 = unlimited).
Gateway:Dicom:AssociationIdleTimeoutSeconds120Seconds before an idle association is closed.
Gateway:Dicom:AcceptUnknownCallingAeTitlestrueWhen true, accepts connections from any calling AE. Set to false and populate AllowedCallingAeTitles to restrict access.
Gateway:Dicom:AllowedCallingAeTitles[]Whitelist of AE Titles allowed to connect when AcceptUnknownCallingAeTitles is false.
Gateway:Dicom:MaxConnectionHistory30Number of past DICOM associations persisted in the database for the Connections dashboard page.
Network Endpoints & TLS Certificates

All listeners (DICOM and HTTP/HTTPS) are configured through Gateway:Network:Endpoints, a named dictionary. Each entry has:

FieldDescription
UrlRequired. Absolute URI. Use dicom://, dicomtls://, http://, or https://.
CertificateOptional. Name of an entry in Gateway:Network:Certificates to use for TLS.
MinTlsVersionTls12 (TLS 1.2+, default) or Tls13 (TLS 1.3 only).

Certificates are defined in Gateway:Network:Certificates:

FieldDescription
SourceFile (only supported source currently).
PathAbsolute or relative path to the PFX/PKCS#12 file.
PasswordPFX password. Prefer the GATEWAY_CERT_PASSWORD environment variable over storing here.
SecurePACS Connection
KeyDefaultDescription
Gateway:SecurePacs:BaseUrlhttps://secure.dicom.linkURL of the SecurePACS server.
Gateway:SecurePacs:PublicKeyIdRequiredOrganization or user public key ID used to encrypt uploads.
Gateway:SecurePacs:BearerTokennullOptional bearer token sent with every request to the SecurePACS server.
Gateway:SecurePacs:HttpTimeout00:05:00Timeout for individual HTTP calls to the SecurePACS server.
Gateway:SecurePacs:StudyMessageTemplatesee belowTemplate for the study message attached to each upload. Placeholders: {AppName}, {AppVersion}, {GatewayAeTitle}, {GatewayPort}, {SourceAeTitle}. Max 4096 characters.
Default template: Study uploaded from {AppName} {AppVersion}.\nReceived by {GatewayAeTitle} on DIMSE port {GatewayPort}.\nSource AE: {SourceAeTitle}.
Storage
KeyDefaultDescription
Gateway:Storage:ProviderLocalStorage backend. Currently only Local (filesystem) is supported.
Gateway:Storage:LocalRootdata/studiesPath where raw DICOM files are temporarily stored.
Gateway:Storage:DeleteRawFilesAfterUploadfalseGlobal safety gate: both this and Cleanup:Enabled must be true for automatic file deletion. Keep false until upload behavior is manually validated.
Gateway:Storage:RetainUploadedStudiesFor7.00:00:00 (7 days)How long an uploaded study's files are kept before the Retention cleanup policy considers them eligible for deletion.
Gateway:Storage:LowSpaceThresholdGb5Free-space threshold in GB that triggers LowSpace cleanup policies.
Database
KeyDefaultDescription
Gateway:Database:ConnectionStringData Source=data/gateway.sqliteSQLite connection string. WAL mode is enabled automatically.
Gateway:DatabaseAdmin:MaintenanceInterval1.00:00:00 (24 h)How often the scheduled maintenance task runs.
Gateway:DatabaseAdmin:EnableScheduledVacuumfalseWhen true, the maintenance task automatically vacuums the database on each run.
Gateway:DatabaseAdmin:MaxRestoreSizeMb1024Maximum size in MB accepted for database restore uploads via the API (1–10240).
Study Settling
KeyDefaultDescription
Gateway:StudySettling:InactivityTimeout00:10:00 (10 min)How long to wait with no new instances before a study is considered settled and queued for upload.
Gateway:StudySettling:ScanInterval00:00:30 (30 sec)How frequently the settling service scans for candidates.
Upload Worker
KeyDefaultDescription
Gateway:UploadWorker:EnabledtrueEnable or disable the SecurePACS upload worker entirely.
Gateway:UploadWorker:MaxAttempts0Maximum upload attempts per study. 0 = unlimited retries.
Gateway:UploadWorker:IdleDelay00:00:10 (10 sec)How long the upload worker waits when no work is available.
Gateway:UploadWorker:ParallelFileUploads1Number of DICOM files uploaded in parallel within a single study (1–4). The worker always processes one study at a time; this only affects per-study file concurrency.
Cleanup
KeyDefaultDescription
Gateway:Cleanup:EnabledfalseActivate the cleanup background worker. Also requires Storage:DeleteRawFilesAfterUpload=true.
Gateway:Cleanup:PolicyRetentionCleanup mode. See table below.
Gateway:Cleanup:ScanInterval01:00:00 (1 hour)How often the cleanup worker scans for eligible studies.
Gateway:Cleanup:BatchSize25Maximum studies processed per cleanup scan.
Gateway:Cleanup:MinimumAgeBeforeLowSpaceCleanup01:00:00 (1 hour)Minimum age a study must have before low-space cleanup considers it, even under critical disk pressure.

Cleanup Policy Values

ValueBehavior
NeverCleanup worker does nothing even if enabled.
RetentionDeletes files for uploaded studies older than Storage:RetainUploadedStudiesFor.
ManualReviewDeletes only studies explicitly approved via POST /studies/{uid}/approve-cleanup.
LowSpaceDeletes oldest uploaded studies when free space falls below LowSpaceThresholdGb, subject to MinimumAgeBeforeLowSpaceCleanup.
RetentionOrLowSpaceCombines Retention and LowSpace — whichever triggers first.
ManualReviewOrLowSpaceCombines ManualReview with an automatic low-space safety net.
Logging
KeyDefaultDescription
Gateway:Logging:ConsoleLevelInformationMinimum log level for console output.
Gateway:Logging:FileLevelInformationMinimum log level for rolling file output.
Gateway:Logging:LogDirectorydata/logsDirectory where rolling log files are written.
Gateway:Logging:ArchiveDirectorydata/logs/archiveDirectory where archived/rotated log files are moved. Used by POST /system/logs/clear-archive.
Gateway:Logging:MaxArchiveFiles14Number of archived log files to retain.
Gateway:Logging:DashboardBufferLimit500Maximum number of recent log entries buffered in memory for the live-log dashboard feature (10–2000).
Status API & Dashboard
KeyDefaultDescription
Gateway:StatusApi:EnabledtrueEnable or disable the web dashboard and status API entirely.
Gateway:StatusApi:AllowNonLoopbackPrefixesfalseAllow binding to non-loopback addresses. When enabling external access, it is strongly recommended to also set a password and enable HTTPS.
Gateway:StatusApi:AdminPasswordHashnullBcrypt-hashed dashboard password. When not set the dashboard runs in open mode (no authentication required). Set via the dashboard Settings → Security page or the POST /auth/change-password endpoint — never edit the hash manually. A startup warning is printed when the gateway is in open mode.
Gateway:StatusApi:SessionVersion1Internal counter incremented automatically on every password change. All existing sessions issued at a lower version are immediately invalidated, providing instant revocation without server-side session storage.
Hosting
KeyDefaultDescription
Gateway:Hosting:EnableSelfRestartfalseWhen true, the gateway attempts to spawn a new process before shutting down during a restart request, enabling self-restart without an external process manager. Set to false (default) when running as a Windows Service, systemd unit, or inside Docker — the process manager handles restart automatically.

Hot Reload

Most settings can be updated at runtime via the PATCH /config API or the Settings page in the dashboard. Changes to Network, Dicom, Storage, Database, DatabaseAdmin, Hosting, and StatusApi require a service restart to take effect. The API response indicates which sections need a restart. Password changes are applied immediately via POST /auth/change-password and take effect without a restart.

HTTPS Setup

Enabling TLS for the Status API and dashboard.

By default the dashboard is served over plain HTTP on loopback only (http://127.0.0.1:11113). When you enable HTTPS, the gateway adds a separate HTTPS endpoint — it does not replace the existing HTTP one. Both listeners run simultaneously: HTTP stays on its original port (e.g. 11113, loopback only), and HTTPS is added on port + 1 (e.g. 11114, all interfaces) by default. This way loopback health checks remain available over plain HTTP while external access uses HTTPS.

You need a PFX/PKCS#12 certificate to enable HTTPS. Self-signed certificates are fine for testing; see the section below for generation commands.

Option A — Via the Dashboard (Recommended)

  1. Open http://127.0.0.1:11113 and navigate to Settings → HTTPS Configuration.
  2. Upload your PFX certificate file with its password and click Upload & Save. The certificate is written to data/certs/ and saved as the GatewayDefault certificate entry.
  3. In the Network settings, add a new HTTPS endpoint referencing GatewayDefault and click Save Changes.
  4. Restart the gateway (via the System → Restart button or the service manager) to activate HTTPS.

Option B — Via the API

Upload the certificate, then add the HTTPS endpoint via PATCH /config, then restart:

# Step 1: Upload the certificate (saves as GatewayDefault, does not add endpoint automatically).
curl -X POST http://127.0.0.1:11113/certs/upload \
  -H "X-Gateway-Admin: true" \
  -F "file=@/path/to/cert.pfx" \
  -F "password=secret"

# Step 2: Add the HTTPS endpoint via config PATCH.
curl -X PATCH http://127.0.0.1:11113/config \
  -H "X-Gateway-Admin: true" \
  -H "Content-Type: application/json" \
  -d '{"Network":{"Endpoints":{"StatusApiHttps":{"Url":"https://0.0.0.0:11114","Certificate":"GatewayDefault"}}}}'

# Step 3: Restart to activate.
curl -X POST http://127.0.0.1:11113/system/restart -H "X-Gateway-Admin: true"

Option C — Manual Edit

Add a StatusApiHttps entry alongside the existing StatusApi entry in appsettings.Local.json, then restart. The HTTP endpoint is untouched:

{
  "Gateway": {
    "Network": {
      "Endpoints": {
        "StatusApi": {
          "Url": "http://127.0.0.1:11113/"
        },
        "StatusApiHttps": {
          "Url": "https://0.0.0.0:11114",
          "Certificate": "GatewayDefault",
          "MinTlsVersion": "Tls12"
        }
      },
      "Certificates": {
        "GatewayDefault": {
          "Source": "File",
          "Path": "data/certs/THUMBPRINT.pfx",
          "Password": "secret"
        }
      }
    },
    "StatusApi": {
      "AllowNonLoopbackPrefixes": true,
      "BearerToken": "your-secret-token"
    }
  }
}

DICOM TLS

The same dual-port pattern applies to the DICOM listener. To run both plain DICOM and DICOM-TLS simultaneously, add a second endpoint alongside the existing one:

{
  "Gateway": {
    "Network": {
      "Endpoints": {
        "DicomListener": {
          "Url": "dicom://0.0.0.0:11112"
        },
        "DicomListenerTls": {
          "Url": "dicomtls://0.0.0.0:11113",
          "Certificate": "GatewayDefault"
        }
      }
    }
  }
}

Convention: TLS port = plain port + 1. Modalities that support DICOM-TLS can connect on the TLS port; legacy modalities continue on the plain port. Both listeners run at the same time with no interaction.

Keep the Password out of Config Files

Set the GATEWAY_CERT_PASSWORD environment variable instead of writing the PFX password to appsettings.Local.json. You can also use the standard .NET env-var override pattern: Gateway__Network__Certificates__GatewayDefault__Password=secret.

Generating a Self-Signed Certificate (Testing Only)

Windows (PowerShell):

$cert = New-SelfSignedCertificate -DnsName "localhost" -CertStoreLocation "cert:\LocalMachine\My"
$pwd  = ConvertTo-SecureString "YourPassword" -AsPlainText -Force
Export-PfxCertificate -Cert $cert -FilePath "data\certs\gateway.pfx" -Password $pwd

Linux / macOS (openssl):

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"
openssl pkcs12 -export -out data/certs/gateway.pfx -inkey key.pem -in cert.pem -passout pass:YourPassword

Validating Without Installing

Use POST /certs/validate to check a PFX file's validity, expiry, key size, and self-signed status before committing it. The dashboard Settings page includes a Validate button for this purpose.

Environment Variables

Override any setting without touching config files.

All configuration keys can be set via environment variables using double-underscores as the hierarchy separator:

Gateway__SecurePacs__PublicKeyId=your-key-id
Gateway__SecurePacs__BaseUrl=https://secure.dicom.link
Gateway__SecurePacs__BearerToken=optional-securepacs-token
Gateway__Storage__DeleteRawFilesAfterUpload=true
Gateway__Cleanup__Enabled=true
Gateway__Network__Certificates__GatewayDefault__Password=cert-password
Gateway__UploadWorker__ParallelFileUploads=4
Gateway__Hosting__EnableSelfRestart=true

Dashboard Password via Environment Variable

The dashboard admin password is stored as a bcrypt hash (AdminPasswordHash), not as a plaintext value. It should be set interactively through the Setup Wizard or the Settings → Security page, not via environment variable. Do not set Gateway__StatusApi__AdminPasswordHash directly unless you are providing a pre-computed bcrypt hash.

For Linux systemd units, add them to the [Service] section:

[Service]
Environment="Gateway__SecurePacs__PublicKeyId=your-key-id"
Environment="Gateway__StatusApi__BearerToken=your-secret-token"

For Windows services, set them via the service properties or in the system environment variables. The gateway picks them up on next start.

Internal Logic

How the gateway ensures study integrity and delivery.

The Study Lifecycle

DICOM lacks an explicit "End of Study" signal. The gateway uses a Settling Mechanism to determine when a study is ready for upload.

[Modality] --(C-STORE)--> [DICOM Listener] | [Local Storage] <-- (Updates timestamp) | [Settling Service] (Checks inactivity) | (Settled after configurable timeout) | [Upload Worker] --(Encrypted Upload)--> [SecurePACS] | [Cleanup Service] (Deletes if policy allows)

Study Status States

StatusMeaning
ReceivingInstances are actively being received from a modality.
SettledNo new instances have arrived within the inactivity timeout; queued for upload.
UploadingThe upload worker is currently processing this study.
UploadedSuccessfully uploaded to SecurePACS.
FailedTransientUpload failed; will be retried according to the retry schedule.
FailedPermanentUpload failed and MaxAttempts was reached. No further automatic retries. Can be manually reset.
PendingDeletionMarked for cleanup; local file deletion is in progress.
DeletedLocal files removed. Study metadata record is retained in the database.

1. Study Settling

The StudySettlingService scans the local database for studies in the Receiving state every StudySettling:ScanInterval (default 30 seconds). If no new instances have been received for StudySettling:InactivityTimeout (default 10 minutes), the study is marked Settled and moved to the upload queue.

2. Secure Upload Worker

The upload worker processes studies one at a time to ensure system stability. It performs the following steps:

  • Metadata Extraction: Scans local files to build a complete SecurePACS study map and study info objects.
  • Local Encryption: Fetches the public key from SecurePACS, generates an ephemeral ECDH P-521 keypair, derives a shared secret, and creates an AES-256-CBC data key. All DICOM files are zstd-compressed (level 3) and AES-CBC encrypted before upload.
  • Multipart Upload: Transmits encrypted DICOM files to SecurePACS. Tune UploadWorker:ParallelFileUploads (1–4) to speed up large study transfers.
  • Finalization: Sends encrypted study map, study info, and metadata to the SecurePACS finalize endpoint.

3. Retry Policy

Failed uploads are retried automatically. Each attempt uses an exponential back-off:

AttemptDelay Before Retry
11 minute
25 minutes
315 minutes
41 hour
53 hours
66 hours
7+24 hours (with jitter)

Set UploadWorker:MaxAttempts = 0 for unlimited retries. Any positive value marks the study FailedPermanent after that attempt count. Failed studies can be manually reset to Settled via the dashboard or POST /studies/{uid}/retry.

4. Cleanup Policies

Once a study is successfully uploaded, the StudyCleanupService manages the local files based on your policy (see the Cleanup configuration table above). Both Cleanup:Enabled = true and Storage:DeleteRawFilesAfterUpload = true must be set for any automatic deletion to occur.

5. Database Maintenance

The gateway automatically maintains its SQLite database. Every DatabaseAdmin:MaintenanceInterval (default 24 hours), the scheduled maintenance task runs:

  • Integrity Check: Verifies the database file is not corrupted.
  • Vacuum (if EnableScheduledVacuum = true): Reclaims unused space and defragments the database.

On-demand vacuum, index rebuild, integrity check, backup, and restore are also available via the Database page in the dashboard or the /db/* API endpoints.

6. Upload Audit Trail

Every upload attempt is persisted in the database with start time, end time, result, error message, and the SecurePACS study ID assigned for that attempt. View the full audit trail for any study via GET /studies/{uid}/attempts or the study detail modal in the dashboard.

Web Dashboard

Built-in browser UI for monitoring and management.

Opening the gateway URL (default http://127.0.0.1:11113) in any modern browser loads the management dashboard. It has five pages accessible from the left sidebar:

Dashboard
Overview cards for DICOM service (AE title & port), queue composition (study statuses with a stacked bar), storage space (gauge showing used vs. free vs. threshold), and SecurePACS target status. Below the cards: a worker status bar, filter controls (status, source AE, UID search), and a Recent Studies table with batch-retry and batch-approve-cleanup actions. A live-activity feed in the sidebar shows incoming events in real time.
Connections
Two tables: Active Connections (currently open DICOM associations with source AE, remote address, called AE, study UID, start time, last activity, and instance count) and Connection History (the last MaxConnectionHistory completed associations stored in the database).
Logs
In-memory log viewer with text filtering, a limit selector (100 / 500 / 1000 entries), a clear button, and an SSE-based live stream — new log lines appear automatically without refreshing. The buffer size is controlled by Logging:DashboardBufferLimit.
Database
Maintenance actions: Vacuum, Rebuild Indexes, Integrity Check (results shown inline).
Backup & Restore: Download a live SQLite backup or upload a backup file to stage a restore (applied on next restart).
Settings
HTTPS Configuration: View the current TLS certificate (subject, expiry, thumbprint), upload and validate a new PFX/PKCS#12 certificate, or generate a self-signed certificate directly from the browser. Changes are saved to appsettings.Local.json; a restart is required to activate HTTPS.

Security: Set or change the dashboard admin password. When no password is set, the gateway runs in open mode and a warning banner is shown.

System Configuration: A full editor for all gateway options. Sections requiring restart are flagged. Click Save Changes to apply.

Dashboard Authentication

When StatusApi:AdminPasswordHash is configured, the dashboard shows a login form on first visit. Sessions last 8 hours with sliding expiration and are stored as an HttpOnly cookie. Changing the password immediately invalidates all existing sessions. When no password is configured, the gateway runs in open mode and prints a security warning at startup — suitable for loopback-only installs during initial setup.

Status API Reference

JSON API for automation and external monitoring.

Authentication

The dashboard uses cookie-based authentication. Two modes of operation exist:

  • Open mode (no password configured): all endpoints are accessible without authentication. Suitable for loopback-only installs during initial setup. A warning is printed at startup and displayed in the dashboard.
  • Password mode (AdminPasswordHash set): a login form is shown on first visit. After successful login a GatewaySession HttpOnly cookie is issued. Sessions last 8 hours with sliding expiration. Changing the password invalidates all existing sessions immediately.
  • Exception — anonymous loopback: GET /health is always accessible from 127.0.0.1 / ::1 without authentication (useful for health-probe scripts).
  • Auth endpoints (/auth/login, /auth/logout, /auth/status) are reachable without a valid session.
  • State-changing requests (POST, PATCH, DELETE) must include the X-Gateway-Admin: true header as an additional safety guard against accidental writes.
  • Rate limiting: POST /auth/login and POST /auth/change-password are limited to 5 requests per 15 minutes per IP. Exceeded attempts receive HTTP 429 with a Retry-After: 900 header.

Authentication Endpoints

MethodEndpointDescription
POST/auth/loginAuthenticate with {"password":"..."}. Sets GatewaySession cookie on success. Rate-limited to 5 per 15 min per IP.
POST/auth/logoutClear the session cookie.
GET/auth/statusReturns { isAuthenticated, user, openMode, insecureCookies }. Always accessible without a session.
POST/auth/change-passwordChange the admin password. Body: {"currentPassword":"...","newPassword":"..."}. New password must be ≥ 8 characters and contain at least one non-letter character. Invalidates all existing sessions. Rate-limited.

System & Status

MethodEndpointDescription
GET/healthLiveness check. Returns { status, instanceId, startupTime, utcNow }. Accessible from loopback without authentication even in password mode.
GET/statusDetailed status: DICOM config, SecurePACS readiness, storage space, worker flags, cleanup evaluation, and queue counts by status (including totalSizeBytes).
GET/system/diagnosticsSystem information: OS, architecture, .NET framework, PID, machine name, processor count, working set (MB), gateway version, instance ID, startup time, and uptime.
POST/system/restartGracefully shuts down the process. When Hosting:EnableSelfRestart = true the gateway spawns a new process before exiting; otherwise the external service manager (systemd, Windows Service) handles the restart.
POST/system/config/resetDeletes appsettings.Local.json and restarts, returning the gateway to Setup Mode. Useful for recovering from a misconfiguration. Loopback-accessible only.
GET/system/logs/exportDownload all files in the configured log directory as a ZIP archive (gateway-logs-YYYYMMDD-HHmmss.zip).
POST/system/logs/clear-archiveDelete all files in Logging:ArchiveDirectory, reclaiming disk space consumed by rotated log archives.

Studies

MethodEndpointDescription
GET/studiesList of up to 50 most recent studies and their current status.
GET/studies/{uid}Full detail for one study: overview, instance list, and upload attempt history. Optional query params: maxInstances (1–500, default 50), maxAttempts (1–200, default 50).
GET/studies/{uid}/attemptsFull upload audit trail for one study. Optional: limit (1–200, default 100).
POST/studies/{uid}/retryReset a failed study to Settled and wake the upload worker. Only works for FailedTransient and FailedPermanent statuses.
POST/studies/{uid}/approve-cleanupMark an uploaded study as approved for manual-review cleanup policies.
DELETE/studies/{uid}Manually delete a study's local files and mark it Deleted. Only allowed for studies in Uploaded status.

Connections

MethodEndpointDescription
GET/connectionsActive DICOM associations and persisted connection history (last MaxConnectionHistory records).

Configuration

MethodEndpointDescription
GET/configRead the full current configuration. Sensitive fields (bearer tokens, certificate passwords) are redacted.
PATCH/configApply a partial configuration update. Body is a JSON object merged into the Gateway section of appsettings.Local.json. Response indicates which sections require a restart.

Logs

MethodEndpointDescription
GET/logsRecent in-memory log entries. Query params: limit (1–1000, default 100), search (text filter).
GET/logs/streamServer-Sent Events (SSE) live log stream. Accepts ?token=<value> as an alternative to the Authorization header for browser EventSource clients.

Database

MethodEndpointDescription
GET/db/integrityRun SQLite PRAGMA integrity_check.
GET/db/backupDownload the current database as a .bak file using the SQLite Online Backup API.
POST/db/vacuumRun SQLite VACUUM to reclaim space.
POST/db/rebuild-indexesRun SQLite REINDEX. (/db/rebuild-indices is an alias.)
POST/db/restoreUpload a SQLite backup file to stage a restore. File is validated before staging. The restore is applied on the next gateway restart. Requires Content-Length header. Size limited by DatabaseAdmin:MaxRestoreSizeMb.

Certificates

MethodEndpointDescription
GET/certs/currentReports current HTTPS certificate status. Finds the first endpoint with an https:// URL (by scheme, not by name). Returns endpoint name, port, scheme, validity, expiry, thumbprint, SAN names, key type/size, and self-signed flag.
POST/certs/validateValidate a PFX/PKCS#12 file without installing it. Multipart form: file (the certificate), password (optional). Returns validation details including warnings for expiring or self-signed certificates.
POST/certs/uploadValidate and save a PFX certificate as GatewayDefault. Saves to data/certs/<thumbprint>.pfx and writes the certificate entry to appsettings.Local.json. Does not automatically add an HTTPS endpoint — configure the desired endpoint separately via PATCH /config or the Settings page, then restart. Multipart form: file, password (optional).
POST/certs/generate-self-signedGenerate a new self-signed RSA certificate, save it as GatewayDefault, and register it in configuration. Useful for testing or internal deployments. Multipart form (all optional): cn (Common Name, default SecurePACS-gateway), days (validity period 1–3650, default 365). The generated PFX has no password. Configure the HTTPS endpoint separately and restart to activate.

Exposing the Dashboard to the Network

To access the dashboard from another machine, set StatusApi:AllowNonLoopbackPrefixes = true. It is strongly recommended to also set an admin password (via Settings → Security) and enable HTTPS before exposing the dashboard on a non-loopback interface. Restrict firewall access to trusted IP ranges.

Usage Scenarios

Theoretical deployment examples.

Scenario A: The Busy Imaging Center

Goal: Minimum delay between scan completion and cloud availability.

  • Config: StudySettling:InactivityTimeout set to 2 minutes.
  • Config: UploadWorker:ParallelFileUploads set to 4.
  • Behavior: Large CT studies (2000+ slices) begin uploading almost immediately after the last image arrives. High parallelism maximizes local fiber internet bandwidth.
Scenario B: Remote Clinic (Unstable Internet)

Goal: Ensure 100% delivery even with daily outages.

  • Config: UploadWorker:MaxAttempts set to 0 (infinite retries).
  • Config: Storage:RetainUploadedStudiesFor set to 14 days.
  • Behavior: The gateway acts as a reliable buffer. If the internet goes down, studies queue up locally. Once the connection is restored, the gateway systematically uploads the backlog while the staff continues scanning.
Scenario C: Research Lab (Review Required)

Goal: Keep raw data locally until a researcher verifies the cloud upload.

  • Config: Cleanup:Policy set to ManualReview.
  • Behavior: Studies are uploaded to SecurePACS. Local files remain on disk. A researcher periodically checks the cloud, then calls POST /studies/{uid}/approve-cleanup to release local disk space.
Scenario D: Secure Remote Access

Goal: Allow IT staff to monitor the gateway dashboard from their office PCs without VPN.

  • Config: Upload a valid TLS certificate via the Settings page (or generate a self-signed one for internal use). Add a StatusApiHttps endpoint in the Network settings pointing to the certificate, then restart. The plain HTTP endpoint on 11113 is kept for loopback health checks.
  • Config: Set StatusApi:AllowNonLoopbackPrefixes = true. Set an admin password via Settings → Security.
  • Config: Open the HTTPS port (e.g. 11114) in the firewall for the allowed IP range only. Port 11113 (HTTP loopback) does not need to be opened externally.
  • Behavior: The dashboard is served over HTTPS on port 11114 from any network interface. Users log in with the admin password; sessions last 8 hours. Plain HTTP remains on port 11113, loopback only, for local health checks.

Troubleshooting

Common issues and their resolutions.

Log Inspection

Logs are the first line of defense. Check data/logs/gateway.log for overall activity and data/logs/gateway.errors.log for failures. The dashboard Logs page provides a filterable view without opening files.

Common Issues

  • Modality can't connect: Check that port 11112 (or your configured DICOM port) is open in Windows Firewall or Linux iptables. Ensure the called AE Title matches the gateway's configured Dicom:AeTitle.
  • Studies stuck in Receiving: This is normal when InactivityTimeout is long and the modality is still sending. Check the Connections dashboard page to confirm whether the association is still active.
  • Upload failures — 404 Not Found: The PublicKeyId is invalid or does not exist on the SecurePACS server. Check the startup banner and the /status API for a validation note.
  • Upload failures — 401 / 403: Incorrect SecurePacs:BearerToken (if configured). Check the SecurePACS server logs for more details.
  • HTTPS not working after save: A restart is required to apply HTTPS changes. Use the dashboard's System → Restart button or your service manager. After restart, connect on the HTTPS port (e.g. 11114), not the original HTTP port. Also verify that the HTTPS endpoint referencing GatewayDefault was saved to configuration (Settings → Network) before restarting.
  • Dashboard returns 401 / login loop: Either no password is configured (open mode, should not redirect) or your session expired. Open /auth/status to check. If openMode: false, log in again at /auth/login. If you forgot the password, use POST /system/config/reset from loopback to delete the local settings and re-run setup.
  • Dashboard returns 403: All state-changing requests require the X-Gateway-Admin: true header. Add it to your API call.
  • Login rate-limited (HTTP 429): More than 5 login attempts were made from the same IP within 15 minutes. Wait for the Retry-After: 900 period to pass.
  • Disk full: Ensure both Cleanup:Enabled = true and Storage:DeleteRawFilesAfterUpload = true. If using ManualReview policy, studies must be individually approved. The dashboard Database → Vacuum can reclaim space from the SQLite file itself.
  • Database restore not applied: Staged restores are applied on the next gateway startup. Restart the service after uploading a restore file.

Privacy & Security

Protecting Patient Health Information (PHI).

Encryption Protocol

The gateway uses the SecurePACS Cryptographic Protocol:

  • An ephemeral ECDH P-521 key pair is generated for each study upload.
  • A 256-bit AES data key is generated using a cryptographically secure random number generator (RandomNumberGenerator.Fill).
  • An ECDH shared secret is derived from the ephemeral private key and the server's P-521 public key.
  • Each DICOM file is zstd-compressed (level 3) and AES-CBC encrypted with the data key before being transmitted.
  • Study metadata (map, info) is also compressed and encrypted. Only the holder of the server-side private key can decrypt it.

Data at Rest

Raw DICOM files are stored in data/studies. These files contain PHI and are not encrypted at rest by the gateway itself. It is strongly recommended to use OS-level disk encryption (BitLocker on Windows, LUKS on Linux) to protect the data directory.

Dashboard Security

The status API defaults to loopback-only access. If you expose it to other network interfaces:

  • Always set an admin password via the dashboard Settings → Security page (POST /auth/change-password).
  • Always enable HTTPS to prevent credential interception (the session cookie is HttpOnly but still transmitted in plaintext over plain HTTP on non-loopback).
  • Restrict firewall access to trusted IP ranges.

Compliance

While the gateway provides the technical tools for HIPAA/GDPR compliance, the end-user is responsible for ensuring the overall deployment (physical security, access controls, network security) meets regulatory requirements.

Technical Reference

Architecture and performance details.

Technology Stack
  • Runtime: .NET 8 ASP.NET Core WebApplication (Kestrel HTTP server).
  • DICOM: fo-dicom for DIMSE services (C-ECHO, C-STORE).
  • Persistence: SQLite with WAL mode for metadata, queue, instances, associations, and upload attempts.
  • Compression: ZstdSharp for DICOM file compression (level 3).
  • Cryptography: .NET built-in ECDiffieHellman, Aes, and RandomNumberGenerator.
  • Logging: NLog with rolling file, console, and in-memory dashboard targets.
  • HTTP Client: IHttpClientFactory for SecurePACS communication.
  • Platforms: Windows x64/ARM64 and Linux x64/ARM64.
File Layout
PathPurpose
appsettings.jsonDefault configuration (do not edit).
appsettings.Local.jsonUser overrides; written by wizard, dashboard, and PATCH /config.
data/gateway.sqliteSQLite database with study queue, instances, associations, and audit trail.
data/studies/Raw DICOM files organized by StudyUID/SeriesUID/SOPInstanceUID.dcm.
data/certs/PFX certificates uploaded via dashboard or API.
data/logs/gateway.logRolling general log.
data/logs/gateway.errors.logRolling warnings and errors only.
data/logs/archive/Rotated/archived log files. Cleared by POST /system/logs/clear-archive.
NLog.configNLog target configuration (log paths, archive count, levels).
Performance Metrics

Values based on a typical quad-core server with SSD storage.

MetricObserved Value
DICOM Receive Speed~30–50 MB/s (network/disk bound)
Encryption Overhead<50 ms per instance
Memory Footprint~150–300 MB (depends on study size and buffer limits)
Database CapacityTested up to 1,000,000 instances