TLDR: I can’t make icecast ssl working with Docker install and the doc describe the installer based setup mainly for that part. Does anyone has an example working config to help me ?
I’ve been installing libretime for the first time recently and wanted to use Terraform to achieve fully automated install so I can reup a clean libretime instance anytime in one command. So I used the docker installation method to have a template based non interactive install.
I managed to do that until the icecast SSL part : everything works fine with a http://domain:8000/main
stream, but I can’t make icecast working with ssl, so the mixed content error prevent usage with chrome basically.
I use nginx reverse and generate the certificates with classic certbot and bundle as described in the doc in one bundle.pem file that I mount in the icecast container, also changing icecast.xml and libretime config.yml accordingly. My conf files are below.
But I still get : INFO connection/get_ssl_certificate No SSL capability on any configured ports
in icecast and no secure stream working.
I read about icecast not necessarily ready for SSL if not compiled correctly and stuff. But I am not sure about the reason of this INFO message and how to fix this.
The default docker install from the doc is really oriented toward non ssl icecast. Is docker install ready for SSL ? Can anyone give me some insights on the way to go from here.
libretime 3.1.0
here is my docker-compose.yml:
version: "3.9"
services:
nginx:
image: nginx
ports:
- 8080:80
depends_on:
- legacy
volumes:
- libretime_assets:/var/www/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
postgres:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: libretime
POSTGRES_PASSWORD: "${postgres-password}"
healthcheck:
test: pg_isready -U libretime
rabbitmq:
image: rabbitmq:3.12-alpine
environment:
RABBITMQ_DEFAULT_VHOST: /libretime
RABBITMQ_DEFAULT_USER: libretime
RABBITMQ_DEFAULT_PASS: "${rabbitmq-password}"
healthcheck:
test: rabbitmq-diagnostics -q ping
playout:
image: ghcr.io/libretime/libretime-playout:${libretime-version}
init: true
ulimits:
nofile: 1024
depends_on:
- rabbitmq
volumes:
- ./config.yml:/etc/libretime/config.yml:ro
- libretime_playout:/app
environment:
LIBRETIME_GENERAL_PUBLIC_URL: "http://nginx"
liquidsoap:
image: ghcr.io/libretime/libretime-playout:${libretime-version}
command: /usr/local/bin/libretime-liquidsoap
init: true
ulimits:
nofile: 1024
ports:
- 8001:8001
- 8002:8002
depends_on:
- rabbitmq
volumes:
- ./config.yml:/etc/libretime/config.yml:ro
- libretime_playout:/app
environment:
LIBRETIME_GENERAL_PUBLIC_URL: "http://nginx"
analyzer:
image: ghcr.io/libretime/libretime-analyzer:${libretime-version}
init: true
ulimits:
nofile: 1024
depends_on:
- rabbitmq
volumes:
- ./config.yml:/etc/libretime/config.yml:ro
- libretime_storage:/srv/libretime
environment:
LIBRETIME_GENERAL_PUBLIC_URL: "http://nginx"
worker:
image: ghcr.io/libretime/libretime-worker:${libretime-version}
init: true
ulimits:
nofile: 1024
depends_on:
- rabbitmq
volumes:
- ./config.yml:/etc/libretime/config.yml:ro
environment:
LIBRETIME_GENERAL_PUBLIC_URL: "http://nginx"
api:
image: ghcr.io/libretime/libretime-api:${libretime-version}
init: true
ulimits:
nofile: 1024
depends_on:
- postgres
- rabbitmq
volumes:
- ./config.yml:/etc/libretime/config.yml:ro
- libretime_storage:/srv/libretime
legacy:
image: ghcr.io/libretime/libretime-legacy:${libretime-version}
init: true
ulimits:
nofile: 1024
depends_on:
- postgres
- rabbitmq
volumes:
- ./config.yml:/etc/libretime/config.yml:ro
- libretime_assets:/var/www/html
- libretime_storage:/srv/libretime
icecast:
image: ghcr.io/libretime/icecast:2.4.4
ports:
# - 8000:8000
- 8443:8443
volumes:
- ./icecast.xml:/etc/icecast2/icecast.xml
- type: bind
source: ./bundle.pem
target: /etc/icecast2/bundle.pem
environment:
ICECAST_SOURCE_PASSWORD: "${icecast-source-password}"
ICECAST_ADMIN_PASSWORD: "${icecast-admin-password}"
ICECAST_RELAY_PASSWORD: "${icecast-relay-password}"
volumes:
postgres_data: {}
libretime_storage: {}
libretime_assets: {}
libretime_playout: {}
then config.yml
:
# See https://libretime.org/docs/admin-manual/setup/configuration/
general:
# The public url.
# > this field is REQUIRED
public_url: "https://${public-domain}"
# The internal API authentication key.
# > this field is REQUIRED
api_key: "${api-key}"
# The Django API secret key. If not defined, the value of [general.api_key] will be
# used as fallback.
# > this field will be REQUIRED starting with LibreTime 4.0.0
secret_key: "${secret-key}"
# List of origins allowed to access resources on the server, the public url
# origin is automatically included.
# > default is []
allowed_cors_origins: []
# The server timezone, should be a lookup key in the IANA time zone database,
# for example Europe/Berlin.
# > default is UTC
timezone: Europe/Paris
# How many hours ahead Playout should cache scheduled media files.
# > default is 1
cache_ahead_hours: 1
# Authentication adaptor to use for the legacy service, specify a class like
# LibreTime_Auth_Adaptor_FreeIpa to replace the built-in adaptor.
# > default is local
auth: local
storage:
# Path of the storage directory.
# > default is /srv/libretime
path: /srv/libretime
database:
# The hostname of the PostgreSQL server.
# > default is localhost
host: postgres
# The port of the PostgreSQL server.
# > default is 5432
port: 5432
# The name of the PostgreSQL database.
# > default is libretime
name: libretime
# The username of the PostgreSQL user.
# > default is libretime
user: libretime
# The password of the PostgreSQL user.
# > default is libretime
password: "${postgres-password}"
rabbitmq:
# The hostname of the RabbitMQ server.
# > default is localhost
host: rabbitmq
# The port of the RabbitMQ server.
# > default is 5672
port: 5672
# The virtual host of RabbitMQ server.
# > default is /libretime
vhost: "/libretime"
# The username of the RabbitMQ user.
# > default is libretime
user: libretime
# The password of the RabbitMQ user.
# > default is libretime
password: "${rabbitmq-password}"
playout:
# Liquidsoap connection host.
# > default is localhost
liquidsoap_host: liquidsoap
# Liquidsoap connection port.
# > default is 1234
liquidsoap_port: 1234
# The format for recordings.
# > must be one of (ogg, mp3)
# > default is ogg
record_file_format: mp3
# The bitrate for recordings.
# > default is 256
record_bitrate: 256
# The samplerate for recordings.
# > default is 44100
record_samplerate: 44100
# The number of channels for recordings.
# > default is 2
record_channels: 2
# The sample size for recordings.
# > default is 16
record_sample_size: 16
liquidsoap:
# Liquidsoap server listen address.
# > default is 127.0.0.1
server_listen_address: 0.0.0.0
# Liquidsoap server listen port.
# > default is 1234
server_listen_port: 1234
# Input harbor listen address.
# > default is ["0.0.0.0"]
harbor_listen_address: ["0.0.0.0"]
# Input harbor tls certificate path.
harbor_ssl_certificate:
# Input harbor tls certificate private key path.
harbor_ssl_private_key:
# Input harbor tls certificate password.
harbor_ssl_password:
stream:
# Inputs sources.
inputs:
# Main harbor input.
main:
# Harbor input public url. If not defined, the value will be generated from
# the [general.public_url] hostname, the input port and mount.
public_url:
# Mount point for the main harbor input.
# > default is main
mount: main
# Listen port for the main harbor input.
# > default is 8001
port: 8001
# Whether the input harbor is secured with the tls certificate.
# > default is false
secure: false
# Show harbor input.
show:
# Harbor input public url. If not defined, the value will be generated from
# the [general.public_url] hostname, the input port and mount.
public_url:
# Mount point for the show harbor input.
# > default is show
mount: show
# Listen port for the show harbor input.
# > default is 8002
port: 8002
# Whether the input harbor is secured with the tls certificate.
# > default is false
secure: false
# Output streams.
outputs:
# Default icecast output
# This can be reused to define multiple outputs without duplicating data
.default_icecast_output: &default_icecast_output
host: icecast
# port: 8000
source_password: "${icecast-source-password}"
admin_password: "${icecast-admin-password}"
name: LibreTime!
description: LibreTime Radio!
website: https://libretime.org
genre: various
# Icecast output streams.
# > max items is 3
icecast:
# The default Icecast output stream
- <<: *default_icecast_output
enabled: true
public_url: https://${public-domain}:8443/main.mp3
mount: main
port: 8443
audio:
format: mp3
bitrate: 256
# You can define extra outputs by reusing the default output using a yaml anchor
- <<: *default_icecast_output
enabled: false
mount: main-ssl
public_url:
port: 8443
audio:
format: mp3
bitrate: 256
- # Whether the output is enabled.
# > default is false
enabled: false
# Output public url, If not defined, the value will be generated from
# the [general.public_url] hostname, the output port and mount.
public_url:
# Icecast server host.
# > default is localhost
host: localhost
# Icecast server port.
# > default is 8000
port: 8000
# Icecast server mount point.
# > this field is REQUIRED
mount: main
# Icecast source user.
# > default is source
source_user: source
# Icecast source password.
# > this field is REQUIRED
source_password: hackme
# Icecast admin user.
# > default is admin
admin_user: admin
# Icecast admin password. If not defined, statistics will not be collected.
admin_password: hackme
# Icecast output audio.
audio:
# Icecast output audio format.
# > must be one of (aac, mp3, ogg, opus)
# > this field is REQUIRED
format: mp3
# Icecast output audio bitrate.
# > must be one of (32, 48, 64, 96, 128, 160, 192, 224, 256, 320)
# > this field is REQUIRED
bitrate: 256
# format=ogg only field: Embed metadata (track title, artist, and show name)
# in the output stream. Some bugged players will disconnect from the stream
# after every songs when playing ogg streams that have metadata information
# enabled.
# > default is false
enable_metadata: false
# Icecast stream name.
name: LibreTime!
# Icecast stream description.
description: LibreTime Radio!
# Icecast stream website.
website: https://libretime.org
# Icecast stream genre.
genre: various
# Shoutcast output streams.
# > max items is 1
shoutcast:
- # Whether the output is enabled.
# > default is false
enabled: false
# Output public url. If not defined, the value will be generated from
# the [general.public_url] hostname and the output port.
public_url:
# Shoutcast server host.
# > default is localhost
host: localhost
# Shoutcast server port.
# > default is 8000
port: 8000
# Shoutcast source user.
# > default is source
source_user: source
# Shoutcast source password.
# > this field is REQUIRED
source_password: hackme
# Shoutcast admin user.
# > default is admin
admin_user: admin
# Shoutcast admin password. If not defined, statistics will not be collected.
admin_password: hackme
# Shoutcast output audio.
audio:
# Shoutcast output audio format.
# > must be one of (aac, mp3)
# > this field is REQUIRED
format: mp3
# Shoutcast output audio bitrate.
# > must be one of (32, 48, 64, 96, 128, 160, 192, 224, 256, 320)
# > this field is REQUIRED
bitrate: 256
# Shoutcast stream name.
name: LibreTime!
# Shoutcast stream website.
website: https://libretime.org
# Shoutcast stream genre.
genre: various
# System outputs.
# > max items is 1
system:
- # Whether the output is enabled.
# > default is false
enabled: false
# System output kind.
# > must be one of (alsa, ao, oss, portaudio, pulseaudio)
# > default is alsa
kind: alsa
then icecast.xml
:
<icecast>
<!-- location and admin are two arbitrary strings that are e.g. visible
on the server info page of the icecast web interface
(server_version.xsl). -->
<location>Paris</location>
<admin>machin@confmail.test</admin>
<!-- IMPORTANT!
Especially for inexperienced users:
Start out by ONLY changing all passwords and restarting Icecast.
For detailed setup instructions please refer to the documentation.
It's also available here: http://icecast.org/docs/
-->
<limits>
<clients>100</clients>
<sources>2</sources>
<queue-size>524288</queue-size>
<client-timeout>30</client-timeout>
<header-timeout>15</header-timeout>
<source-timeout>10</source-timeout>
<!-- If enabled, this will provide a burst of data when a client
first connects, thereby significantly reducing the startup
time for listeners that do substantial buffering. However,
it also significantly increases latency between the source
client and listening client. For low-latency setups, you
might want to disable this. -->
<burst-on-connect>1</burst-on-connect>
<!-- same as burst-on-connect, but this allows for being more
specific on how much to burst. Most people won't need to
change from the default 64k. Applies to all mountpoints -->
<burst-size>65535</burst-size>
</limits>
<authentication>
<!-- Sources log in with username 'source' -->
<source-password>${icecast-source-password}</source-password>
<!-- Relays log in with username 'relay' -->
<relay-password>${icecast-relay-password}</relay-password>
<!-- Admin logs in with the username given below -->
<admin-user>admin</admin-user>
<admin-password>${icecast-admin-password}</admin-password>
</authentication>
<!-- set the mountpoint for a shoutcast source to use, the default if not
specified is /stream but you can change it here if an alternative is
wanted or an extension is required
<shoutcast-mount>/live.nsv</shoutcast-mount>
-->
<!-- Uncomment this if you want directory listings -->
<!--
<directory>
<yp-url-timeout>15</yp-url-timeout>
<yp-url>http://dir.xiph.org/cgi-bin/yp-cgi</yp-url>
</directory>
-->
<!-- This is the hostname other people will use to connect to your server.
It affects mainly the urls generated by Icecast for playlists and yp
listings. You MUST configure it properly for YP listings to work!
-->
<hostname>${public-domain}</hostname>
<!-- You may have multiple <listen-socket> elements -->
<listen-socket>
<port>8000</port>
<!-- <bind-address>127.0.0.1</bind-address> -->
<!-- <shoutcast-mount>/stream</shoutcast-mount> -->
</listen-socket>
<listen-socket>
<port>8443</port>
<ssl>1</ssl>
</listen-socket>
<!-- Global header settings
Headers defined here will be returned for every HTTP request to Icecast.
The ACAO header makes Icecast public content/API by default
This will make streams easier embeddable (some HTML5 functionality needs it).
Also it allows direct access to e.g. /status-json.xsl from other sites.
If you don't want this, comment out the following line or read up on CORS.
-->
<http-headers>
<header name="Access-Control-Allow-Origin" value="*" />
</http-headers>
<!-- Relaying
You don't need this if you only have one server.
Please refer to the documentation for a detailed explanation.
-->
<!--<master-server>127.0.0.1</master-server>-->
<!--<master-server-port>8001</master-server-port>-->
<!--<master-update-interval>120</master-update-interval>-->
<!--<master-password>hackme</master-password>-->
<!-- setting this makes all relays on-demand unless overridden, this is
useful for master relays which do not have <relay> definitions here.
The default is 0 -->
<!--<relays-on-demand>1</relays-on-demand>-->
<!--
<relay>
<server>127.0.0.1</server>
<port>8080</port>
<mount>/example.ogg</mount>
<local-mount>/different.ogg</local-mount>
<on-demand>0</on-demand>
<relay-shoutcast-metadata>0</relay-shoutcast-metadata>
</relay>
-->
<!-- Mountpoints
Only define <mount> sections if you want to use advanced options,
like alternative usernames or passwords
-->
<!-- Default settings for all mounts that don't have a specific <mount type="normal">.
-->
<!--
<mount type="default">
<public>0</public>
<intro>/server-wide-intro.ogg</intro>
<max-listener-duration>3600</max-listener-duration>
<authentication type="url">
<option name="mount_add" value="http://auth.example.org/stream_start.php"/>
</authentication>
<http-headers>
<header name="foo" value="bar" />
</http-headers>
</mount>
-->
<mount type="default">
<charset>UTF-8</charset>
</mount>
<!-- Normal mounts -->
<!--
<mount type="normal">
<mount-name>/example-complex.ogg</mount-name>
<username>othersource</username>
<password>hackmemore</password>
<max-listeners>1</max-listeners>
<dump-file>/tmp/dump-example1.ogg</dump-file>
<burst-size>65536</burst-size>
<fallback-mount>/example2.ogg</fallback-mount>
<fallback-override>1</fallback-override>
<fallback-when-full>1</fallback-when-full>
<intro>/example_intro.ogg</intro>
<hidden>1</hidden>
<public>1</public>
<authentication type="htpasswd">
<option name="filename" value="myauth"/>
<option name="allow_duplicate_users" value="0"/>
</authentication>
<http-headers>
<header name="Access-Control-Allow-Origin" value="http://webplayer.example.org" />
<header name="baz" value="quux" />
</http-headers>
<on-connect>/home/icecast/bin/stream-start</on-connect>
<on-disconnect>/home/icecast/bin/stream-stop</on-disconnect>
</mount>
-->
<!--
<mount type="normal">
<mount-name>/auth_example.ogg</mount-name>
<authentication type="url">
<option name="mount_add" value="http://myauthserver.net/notify_mount.php"/>
<option name="mount_remove" value="http://myauthserver.net/notify_mount.php"/>
<option name="listener_add" value="http://myauthserver.net/notify_listener.php"/>
<option name="listener_remove" value="http://myauthserver.net/notify_listener.php"/>
<option name="headers" value="x-pragma,x-token"/>
<option name="header_prefix" value="ClientHeader."/>
</authentication>
</mount>
-->
<fileserve>1</fileserve>
<paths>
<!-- basedir is only used if chroot is enabled -->
<basedir>/usr/share/icecast2</basedir>
<!-- Note that if <chroot> is turned on below, these paths must both
be relative to the new root, not the original root -->
<logdir>/var/log/icecast2</logdir>
<webroot>/usr/share/icecast2/web</webroot>
<adminroot>/usr/share/icecast2/admin</adminroot>
<!-- <pidfile>/usr/share/icecast2/icecast.pid</pidfile> -->
<!-- Aliases: treat requests for 'source' path as being for 'dest' path
May be made specific to a port or bound address using the "port"
and "bind-address" attributes.
-->
<!--
<alias source="/foo" destination="/bar"/>
-->
<!-- Aliases: can also be used for simple redirections as well,
this example will redirect all requests for http://server:port/ to
the status page
-->
<alias source="/" destination="/status.xsl" />
<ssl-certificate>/etc/icecast2/bundle.pem</ssl-certificate>
<!-- The certificate file needs to contain both public and private part.
Both should be PEM encoded.
<ssl-certificate>/usr/share/icecast2/bundle.pem</ssl-certificate>
-->
</paths>
<logging>
<accesslog>access.log</accesslog>
<errorlog>error.log</errorlog>
<!-- <playlistlog>playlist.log</playlistlog> -->
<loglevel>3</loglevel> <!-- 4 Debug, 3 Info, 2 Warn, 1 Error -->
<logsize>10000</logsize> <!-- Max size of a logfile -->
<!-- If logarchive is enabled (1), then when logsize is reached
the logfile will be moved to [error|access|playlist].log.DATESTAMP,
otherwise it will be moved to [error|access|playlist].log.old.
Default is non-archive mode (i.e. overwrite)
-->
<!-- <logarchive>1</logarchive> -->
</logging>
<security>
<chroot>0</chroot>
<!--
<changeowner>
<user>nobody</user>
<group>nogroup</group>
</changeowner>
-->
</security>
</icecast>