Hello, I know this is the most famous question when developing Litium application, the installation process for apps and dependencies through Docker.
I switched to Linux this christmas and I thought that docker should be my least problem. Everything works except installing apps. Docker Desktop on Windows and Mac does alot of things out of the box. With native Docker you have to set it up all yourself. I got so far so that I can access the apps and get redirected to Litium BO for installation, then comes the “app could not be installed” banner and the logs below from the app and LitiumAccelerator
direct-payment.log:
2025-02-07 15:07:10.1003 [App:01] [9f7d1ff3e0fd3afff9493a7fdf037843] [ERROR] [.NET ThreadPool Worker] Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler - Exception occurred while processing message. System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'System.String'.
---> System.Net.Http.HttpRequestException: Name or service not known (pk-produkter.localtest.me:5001)
---> System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
2025-02-07 15:07:10.1103 [App:01] [9f7d1ff3e0fd3afff9493a7fdf037843] [ERROR] [.NET ThreadPool Worker] Microsoft.AspNetCore.Server.Kestrel - Connection id "0HNA7H3LABFC0", Request id "0HNA7H3LABFC0:00000002": An unhandled exception was thrown by the application. System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'System.String'.
---> System.Net.Http.HttpRequestException: Name or service not known (pk-produkter.localtest.me:5001)
---> System.Net.Sockets.SocketException (0xFFFDFFFF): Name or service not known
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request)
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
litium.log:
2025-02-07 11:52:37.4562 [App:01] [fd590b0e3dad2e06f27244d5831b3a5c] [ERROR] [.NET ThreadPool Worker] Litium.Web.Administration.Web>
at Litium.Application.AppManagement.AppManagementServiceImpl.GetMetadataAsync(String url)
at Litium.Web.Administration.WebApi.Settings.Controllers.AppManagementController.InstallGet(String url)
I had to configure a bit more to make dns work properly and this is my docker-compose.yml:
# Docker compose below sets up the containers needed to run Litium locally:
networks:
custom_bridge:
ipam:
driver: default
config:
- subnet: 192.168.100.0/24
services:
dnsresolver:
# https://github.com/cytopia/docker-bind
container_name: dnsresolver
image: cytopia/bind:stable-0.28
ports:
- "53:53/tcp"
- "53:53/udp"
networks:
custom_bridge:
ipv4_address: 192.168.100.53
environment:
- DNS_CNAME=*.localtest.me=host.docker.internal
- DNS_FORWARDER=8.8.8.8 # Should point to a DNS Server for Docker Desktop its 192.168.65.7 depending on version.
dns:
- 8.8.8.8
restart: unless-stopped
netshoot:
container_name: netshoot
image: nicolaka/netshoot
dns: 192.168.100.53
networks:
- custom_bridge
command: ["sleep", "infinity"] # Keeps the container running
restart: unless-stopped
elasticsearch:
container_name: elastic
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
depends_on:
- dnsresolver
dns:
- 192.168.100.53
networks:
- custom_bridge
restart: unless-stopped
user: root
ports:
- "9200:9200"
environment:
- discovery.type=single-node
# Allocate 2GB RAM instead of the default 512MB
# comment out the line below for additional memory allocation
# - "ES_JAVA_OPTS=-Xms2g -Xmx2g"
volumes:
- ./volumes/elasticsearch/data:/usr/share/elasticsearch/data
entrypoint:
- /bin/sh
- -c
# The accelerator implementation of Elasticsearch require the analysis-dynamic-synonym.
# The plugin refreshes the list of synonyms in Elasticsearch every minute allowing synonyms
# to be added/modified in Litium backoffice and updated in Elasticsearch without downtime.
# Internet access is not working so we try to install the plugin by downloading it seperatly and placing it in /data/plugin manually
# The original link to zip is https://github.com/Tasteful/elasticsearch-analysis-dynamic-synonym/releases/download/v7.6.2/elasticsearch-analysis-dynamic-synonym.zip
- "chown -R 1000:1000 /usr/share/elasticsearch/data &&./bin/elasticsearch-plugin list | grep -q analysis-dynamic-synonym || ./bin/elasticsearch-plugin install -b file:///usr/share/elasticsearch/data/plugin/elasticsearch-analysis-dynamic-synonym.zip; /usr/local/bin/docker-entrypoint.sh"
kibana:
container_name: kibana
# The Kibana image tries, by default, to connect to a host/container called elasticsearch.
image: docker.elastic.co/kibana/kibana:7.6.2
depends_on:
- elasticsearch
networks:
- custom_bridge
restart: unless-stopped
ports:
- "5601:5601"
synonymserver:
container_name: synonym
# Synonym server to provide elasticsearch with synonyms.
image: registry.litium.cloud/apps/synonym-server:1.2.0
restart: unless-stopped
ports:
- "9210:80"
networks:
- custom_bridge
environment:
- DataFolder=/app_data
volumes:
- ./volumes/synonymserver/data:/app_data
redis:
container_name: redis
image: redis:5.0.5-alpine
restart: unless-stopped
ports:
- "6379:6379"
networks:
- custom_bridge
mailhog:
container_name: mailhog
image: mailhog/mailhog:latest
restart: unless-stopped
logging:
driver: 'none'
ports:
- "1025:1025" # SMTP-server
- "8025:8025" # Web UI
networks:
- custom_bridge
sqlserver:
container_name: sqlserver
image: mcr.microsoft.com/mssql/server:2019-latest
environment:
- SA_PASSWORD=Pass@word
- ACCEPT_EULA=Y
restart: unless-stopped
user: root
ports:
# Make the SQL Container available on port 5434 to not conflict with a previously installed local SQL instance.
# If you do not have SQL Server installed you can use 1433:1433 as mapping and skip port number in connectionstrings.
- "5434:1433"
networks:
- custom_bridge
volumes:
# Map [local directory:container directory] - this is so that db/log files are
# stored on the "host" (your local computer, outside of container) and thereby
# persisted when container restarts.
# by starting local path with "." it gets relative to current folder, meaning that the database
# files will be on your computer in the same directory as you have this docker-compose.yaml file
- ./data/mssql/data:/var/opt/mssql/data
- ./data/mssql/log:/var/opt/mssql/log
entrypoint:
# Due to an issue with the sqlserver image, permissions to db-files may be lost on container restart
# by using the specific permissions_check entrypoint you assert that permissions are set on every restart
- /bin/sh
- -c
- "/opt/mssql/bin/permissions_check.sh && /opt/mssql/bin/sqlservr"
briqpay-payment:
container_name: briqpay
image: registry.litium.cloud/apps/briqpay-payment:1.9.4
restart: unless-stopped
ports:
- "10030:80"
- "10031:443"
networks:
- custom_bridge
dns: 192.168.100.53
environment:
# Enable HTTPS binding
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=10031
# Configuration for HTTPS inside the container, exported dotnet dev-certs with corresponding password
- ASPNETCORE_Kestrel__Certificates__Default__Password=SuperSecretPassword
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/localhost.pfx
# Folder for the configuraiton, this is volume-mapped
- CONFIG_PATH=/app_config
# Folder where logfiles should be placed, this is volume-mapped
- APP_LOG_PATH=/logs
# Don't validate certificates
- AppConfiguration__ValidateCertificate=false
# Disable callbacks
- AppConfiguration__DisableCallbacks=true
# Url to this app
- AppMetadata__AppUrl=https://briqpay-app.localtest.me:10031
# Url to the litium installation
- LitiumApi__ApiUrl=https://pk-produkter.localtest.me:5001
volumes:
- ./data/briqpay-payment/config:/app_config
- ./data/briqpay-payment/data:/app_data
- ./data/briqpay-payment/logs:/logs
- ./data/briqpay-payment/DataProtection-Keys:/root/.aspnet/DataProtection-Keys
- ./data/https:/https:ro
direct-payment:
container_name: payment
image: registry.litium.cloud/apps/direct-payment:1.4.1
restart: unless-stopped
ports:
- "10010:80"
- "10011:443"
networks:
- custom_bridge
dns:
- 192.168.100.53
environment:
# Enable HTTPS binding
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=10011
# Configuration for HTTPS inside the container, exported dotnet dev-certs with corresponding password
- ASPNETCORE_Kestrel__Certificates__Default__Password=SuperSecretPassword
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/localhost.pfx
# Folder for the configuraiton, this is volume-mapped
- CONFIG_PATH=/app_config
# Folder where logfiles should be placed, this is volume-mapped
- APP_LOG_PATH=/logs
# Don't validate certificates
- AppConfiguration__ValidateCertificate=false
# Url to this app
- AppMetadata__AppUrl=https://payment-app.localtest.me:10011
# Url to the litium installation
- LitiumApi__ApiUrl=https://pk-produkter.localtest.me:5001
volumes:
- ./data/direct-payment/config:/app_config
- ./data/direct-payment/data:/app_data
- ./data/direct-payment/logs:/logs
- ./data/direct-payment/DataProtection-Keys:/root/.aspnet/DataProtection-Keys
- ./data/https:/https:ro
direct-shipment:
container_name: shipment
image: registry.litium.cloud/apps/direct-shipment:1.2.0
ports:
- "10020:80"
- "10021:443"
networks:
- custom_bridge
dns:
- 192.168.100.53
environment:
# Enable HTTPS binding
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=10021
# Configuration for HTTPS inside the container, exported dotnet dev-certs with corresponding password
- ASPNETCORE_Kestrel__Certificates__Default__Password=SuperSecretPassword
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/localhost.pfx
# Folder for the configuraiton, this is volume-mapped
- CONFIG_PATH=/app_config
# Folder where logfiles should be placed, this is volume-mapped
- APP_LOG_PATH=/logs
# Don't validate certificates
- AppConfiguration__ValidateCertificate=false
# Url to this app
- AppMetadata__AppUrl=https://shipment-app.localtest.me:10021
# Url to the litium installation
- LitiumApi__ApiUrl=https://pk-produkter.localtest.me:5001
volumes:
- ./data/direct-shipment/config:/app_config
- ./data/direct-shipment/data:/app_data
- ./data/direct-shipment/logs:/logs
- ./data/direct-shipment/DataProtection-Keys:/root/.aspnet/DataProtection-Keys
- ./data/https:/https:ro
Is there any one out there who have good knowledge about docker and network?
I think that my problem is that the app cant talk back to the host eg the Litium Accelerator.
Litium version: 8.12