{"id":78,"date":"2025-08-27T00:00:00","date_gmt":"2025-08-26T15:00:00","guid":{"rendered":"https:\/\/www.eqmaker.kr\/en\/?p=78"},"modified":"2026-08-18T23:56:29","modified_gmt":"2026-08-18T14:56:29","slug":"wowza-self-signed-certificate","status":"publish","type":"post","link":"https:\/\/www.eqmaker.kr\/en\/wowza-self-signed-certificate\/","title":{"rendered":"How to Create a Self-Signed HTTPS Certificate and Apply It to Wowza"},"content":{"rendered":"\n<p id=\"EQArticleSummary\">To send an <abbr title=\"Hypertext Transfer Protocol Secure\">HTTPS<\/abbr> <abbr title=\"HTTP Live Streaming\">HLS<\/abbr> stream, the streaming program must trust the server&#8217;s self-signed certificate. This article explains how to create a certificate and private key with Python and how to register the certificate in the Java cacerts used by Wowza Streaming Engine.<\/p>\n\n<section>\n    <h2 id=\"HlsHttpsCertificates\">HTTPS Certificates and HLS<\/h2>\n    <p><dfn>HLS<\/dfn> is a streaming method that uses <abbr title=\"Hypertext Transfer Protocol\">HTTP<\/abbr>, which is widely used for web services, to <a href=\"https:\/\/www.eqmaker.kr\/en\/rtmp-vs-hls-for-youtube-live-streaming\/\" title=\"Differences Between RTMP and HLS Live Streaming and How to Choose\">send video data and playlists<\/a>.<\/p>\n    <p>Several security problems arose with HTTP, which has been used since the early days of the Internet. <dfn>HTTPS<\/dfn> became widely used to address these problems. It is now the standard method for modern Internet transmission. HTTPS encrypts transmitted data with a <strong>key<\/strong>. It uses a <strong>certificate<\/strong> to verify the identity of the other party. This improves the reliability of the communication.<\/p>\n    <p>These security measures are very helpful in a real service environment, but not in a <a href=\"https:\/\/www.eqmaker.kr\/en\/obs-youtube-live-hls-capture-debug\/\" title=\"Capture an OBS HLS PUSH Stream\" hreflang=\"en\">development environment<\/a>. A certificate in a test environment is not officially registered. This causes problems in the verification process and makes integration fail.<\/p>\n    <p>Therefore, in a test environment where a publicly trusted certificate cannot be used, you must create a <strong>self-signed certificate and private key<\/strong> and apply them to the test server. You must also separately register the certificate so that the connecting program trusts it.<\/p>\n    <p>This article explains how to use Python to create a self-signed certificate and private key for a private HLS PUSH server such as <code>PushCap<\/code>. It also explains how to register the certificate in the Java trust store used by Wowza Streaming Engine (hereafter called WSE), and send an HTTPS HLS PUSH stream.<\/p>\n<\/section>\n\n<section>\n    <h2 id=\"GenerateCertificateWithPython\">How to Create a Certificate with Python<\/h2>\n    <section>\n    <h3 id=\"PreparePythonEnvironment\">Prepare the Python Environment<\/h3>\n    <ol>\n        <li><strong>Install Python<\/strong>\n            <p>This example uses Python. Therefore, Python must be installed on the PC where you will create the key and certificate.<\/p>\n        <\/li>\n        <li><strong>Install the additional package<\/strong>\n            <p>Use the following command to install the <code>cryptography<\/code> package required to run the program.<\/p>\n            <code class=\"line\">py -m pip install cryptography<\/code>\n        <\/li>\n    <\/ol>\n    <\/section>\n    <section>\n    <h3 id=\"ProgramFile\">Create the Program File<\/h3>\n            <p>Create a suitable directory. Copy the code below and save it as <code>GenCert.py<\/code>.<\/p>\n<pre><code>from cryptography import x509\nfrom cryptography.x509.oid import NameOID\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import rsa\nfrom cryptography.hazmat.primitives import serialization\nimport datetime\n\n# Enter the domain name here. This is the address entered in the streaming program.\ndomain_name = u\"b.upload.youtube.com\"\n\n# 1. Create a private key\nkey = rsa.generate_private_key(\n    public_exponent=65537,\n    key_size=2048,\n)\n\n# 2. Save the private key to a file (key.pem)\nwith open(\"key.pem\", \"wb\") as f:\n    f.write(key.private_bytes(\n        encoding=serialization.Encoding.PEM,\n        format=serialization.PrivateFormat.TraditionalOpenSSL,\n        encryption_algorithm=serialization.NoEncryption(),\n    ))\n\n# 3. Set the certificate information for self-signing (change the Common Name)\nsubject = issuer = x509.Name([\n    x509.NameAttribute(NameOID.COUNTRY_NAME, u\"KR\"),\n    x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u\"Jeju-do\"),\n    x509.NameAttribute(NameOID.LOCALITY_NAME, u\"Mola-si\"),\n    x509.NameAttribute(NameOID.ORGANIZATION_NAME, u\"EQMaker\"),\n    x509.NameAttribute(NameOID.COMMON_NAME, domain_name),\n])\n\n# 4. Create and sign the certificate\ncert = x509.CertificateBuilder().subject_name(\n    subject\n).issuer_name(\n    issuer\n).public_key(\n    key.public_key()\n).serial_number(\n    x509.random_serial_number()\n).not_valid_before(\n    datetime.datetime.now(datetime.timezone.utc)\n).not_valid_after(\n    datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)\n).add_extension(\n    x509.SubjectAlternativeName([x509.DNSName(domain_name)]),\n    critical=False,\n).sign(key, hashes.SHA256())\n\n# 5. Save the certificate to a file (cert.pem)\nwith open(\"cert.pem\", \"wb\") as f:\n    f.write(cert.public_bytes(serialization.Encoding.PEM))\n\nprint(f\"'{domain_name}'  cert.pem \/ key.pem created.\")\n<\/code><\/pre>\n            <p>Replace <samp>b.upload.youtube.com<\/samp> with the host name of the HTTPS <abbr title=\"Uniform Resource Locator\">URL<\/abbr> you want to use. In other words, the server with this certificate claims that it is <code>b.upload.youtube.com<\/code>.<\/p>\n    <\/section>\n\n    <section>\n        <h3 id=\"GenerateCertificate\">Create the Certificate<\/h3>\n            <p>In a console window, move to the directory that contains <code>GenCert.py<\/code>. Run the code. If the message <samp>created<\/samp> appears as shown below, the cryptographic key and certificate were created successfully.<\/p>\n<pre><samp>Microsoft Windows [Version 10.0.20348.4052]\n(c) Microsoft Corporation. All rights reserved.\nD:\\&gt;<kbd>cd HLSWEB<\/kbd>\nD:\\HLSWEB&gt;<kbd>py GenCert.py<\/kbd>\n'b.upload.youtube.com' cert.pem \/ key.pem created.<\/samp><\/pre>\n        <p>Copy the generated <code>cert.pem<\/code> and <code>key.pem<\/code> files to the directory where <code>PushCap.py<\/code> runs. If you another type of receiving server, register the certificate and key files on that server.<\/p>\n    <\/section>\n    <p>If you use a streaming program such as <abbr title=\"Open Broadcaster Software\">OBS<\/abbr> that does not have a separate certificate and key verification function, you can send an HTTPS HLS stream without additional work. However, WSE verifies whether the server certificate is trusted. Because the certificate is not publicly trusted, the additional registration procedure below is required.<\/p>\n<\/section>\n\n<section>\n    <h2 id=\"ApplyCertificateToWowza\">Apply a Private Certificate to Wowza Streaming Engine<\/h2>\n    <p>Commercial streaming programs such as WSE may perform their own additional certificate verification. A self-signed certificate is not registered in the default trust store. Therefore, you must directly register the certificate presented by the PushCap server in WSE&#8217;s Java trust store.<\/p>\n    <section>\n    <h3 id=\"StepToApply\">Procedure for Applying a Private Certificate to Wowza Streaming Engine<\/h3>\n    <ol>\n        <li><strong>Stop the WSE service<\/strong><\/li>\n        <li><strong>Open a console<\/strong>: Open a console, such as a DOS window, with administrator privileges.<\/li>\n        <li><strong>Move to the Java tool directory<\/strong>\n            <p>Move to the Java tool directory installed with WSE. The default path is <code>[WSE default installation path]\/jre\/bin<\/code>. The default path may differ if you use a separately installed Java version or a different WSE version. Check the path carefully.<\/p>\n        <\/li>\n        <li>\n            <strong>Register the certificate file<\/strong>\n            <p>The <code>bin<\/code> directory contains an executable file named <code>keytool<\/code>. Enter the following command to register the certificate file.<\/p>\n            <code class=\"line\">keytool -importcert -alias \"[certificate name]\" -keystore \"[certificate store]\" -storepass changeit -file \"[certificate file]\"<\/code>\n            <dl>\n                <dt>[certificate name]<\/dt>\n                <dd>The name of the certificate to use in WSE. You may choose any name.<\/dd>\n                <dt>[certificate store]<\/dt>\n                <dd>The location where the certificate will be stored. It is the certificate store inside the <abbr title=\"Java Runtime Environment\">JRE<\/abbr> directory used by WSE. The default path is <code>[WSE installation path]\\jre\\lib\\security\\cacerts<\/code>.<\/dd>\n                <dt>[certificate file]<\/dt>\n                <dd>The path and file name of the certificate file (<code>.pem<\/code>) to register<\/dd>\n            <\/dl>\n            <p><code>changeit<\/code> is the initial password of the Java <code>cacerts<\/code> trust store. If the administrator changed the password, enter the actual password instead.<\/p>\n        <\/li>\n    <\/ol>\n    <\/section>\n\n    <section>\n    <h3 id=\"WSECertificateExample\">Example of Applying and Verifying a Certificate in Wowza Streaming Engine<\/h3>\n    <p>The following is an actual example of applying a private certificate to WSE on Windows. The environment is as follows.<\/p>\n    <dl>\n        <dt>Operating system<\/dt>\n        <dd>Windows Server 2022<\/dd>\n        <dt>WSE version<\/dt>\n        <dd>4.8.25+2<\/dd>\n        <dt>Certificate file path<\/dt>\n        <dd><code>D:\\HLSWEB\\cert.pem<\/code><\/dd>\n    <\/dl>\n\n    <ol>\n        <li>Open a console window, such as a DOS window, with administrator privileges.<\/li>\n        <li>\n            <strong>Stop the WSE service<\/strong>\n<pre><samp>C:\\&gt;<kbd>sc stop WowzaStreamingEngine4825+2<\/kbd>\n\nSERVICE_NAME: WowzaStreamingEngine4825+2\n        TYPE               : 10  WIN32_OWN_PROCESS\n        STATE              : 3  STOP_PENDING\n                                (STOPPABLE, PAUSABLE, ACCEPTS_SHUTDOWN)\n        WIN32_EXIT_CODE    : 0  (0x0)\n        SERVICE_EXIT_CODE  : 0  (0x0)\n        CHECKPOINT         : 0x0\n        WAIT_HINT          : 0x7d0<\/samp><\/pre>\n        <\/li>\n\n        <li><strong>Register the certificate<\/strong>\n<pre><samp>C:\\&gt;Program Files\\Wowza Media Systems\\Wowza Streaming Engine 4.8.25+2\\jre\\bin&gt;<kbd>keytool.exe -importcert -alias \"YouTubeLocal\" -keystore \"C:\\Program Files\\Wowza Media Systems\\Wowza Streaming Engine 4.8.25+2\\jre\\lib\\security\\cacerts\" -storepass changeit -file \"D:\\HLSWEB\\cert.pem\"<\/kbd>\nWarning: use -cacerts option to access cacerts keystore\nOwner: CN=b.upload.youtube.com, O=EQMaker, L=Mola-si, ST=Jeju-do, C=KR\nIssuer: CN=b.upload.youtube.com, O=EQMaker, L=Mola-si, ST=Jeju-do, C=KR\nSerial number: 389c81b7d9e5452c8cbace6436a99aff004376\nValid from: Mon Aug 25 23:34:59 KST 2025 until: Tue Aug 25 23:34:59 KST 2026\nCertificate fingerprints:\n         SHA1: AA:BB:CC:DD:EE:00:AA:BB:CC:DD:EE:00:65:33:A0:A8:44:55:C0:54\n         SHA256: AA:BB:CC:DD:EE:00:AA:BB:CC:DD:EE:FF:00:AA:BB:CC:DD:EE:25:9E:AD:00:54:DE:D0:AE:52:97:1C:A1:85:59\nSignature algorithm name: SHA256withRSA\nSubject Public Key Algorithm: 2048-bit RSA key\nVersion: 3\n\nExtensions:\n\n#1: ObjectId: 2.5.29.17 Criticality=false\nSubjectAlternativeName [\n  DNSName: b.upload.youtube.com\n]\n\nTrust this certificate? [no]:  <kbd>yes<\/kbd>\nCertificate was added to keystore<\/samp><\/pre>\n        <\/li>\n\n        <li><strong>Verify the certificate registration<\/strong>\n<pre><samp>C:\\Program Files\\Wowza Media Systems\\Wowza Streaming Engine 4.8.25+2\\jre\\bin><kbd>keytool -list -cacerts<\/kbd>\nEnter keystore password:<kbd>Enter<\/kbd>\n\n*****************  WARNING WARNING WARNING  *****************\n* The integrity of the information stored in your keystore  *\n* has NOT been verified!  In order to verify its integrity, *\n* you must provide your keystore password.                  *\n*****************  WARNING WARNING WARNING  *****************\n\nKeystore type: JKS\nKeystore provider: SUN\n\nYour keystore contains 93 entries\n\n... (earlier lines omitted) ...\nyoutubelocal, 2025 Aug 26, trustedCertEntry,\nCertificate fingerprint (SHA-256): AA:BB:CC:DD:EE:00:AA:BB:CC:DD:EE:FF:00:AA:BB:CC:DD:EE:25:9E:AD:00:54:DE:D0:AE:52:97:1C:A1:85:59\n... (omitted) ...<\/samp><\/pre>\n            <p>If a certificate with the registered name, <samp>youtubelocal<\/samp> in this example, exists as shown above, it was registered successfully.<\/p>\n        <\/li>\n        <li><strong>Restart the WSE service<\/strong>\n<pre><samp>C:\\&gt;<kbd>sc start WowzaStreamingEngine4825+2<\/kbd>\nSERVICE_NAME: WowzaStreamingEngine4825+2\n        TYPE               : 10  WIN32_OWN_PROCESS\n        STATE              : 2  START_PENDING\n                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)\n        WIN32_EXIT_CODE    : 0  (0x0)\n        SERVICE_EXIT_CODE  : 0  (0x0)\n        CHECKPOINT         : 0x0\n        WAIT_HINT          : 0x7d0\n        PID                : 4356\n        FLAGS              :<\/samp><\/pre>\n        <\/li>\n    <\/ol>\n<\/section>\n<\/section>\n\n<section>\n    <h2>FAQ<\/h2>\n    <dl>\n        <dt>Why is a certificate needed for HLS transmission?<\/dt>\n        <dd>\n            <p>HLS itself does not always require a certificate. However, a transmission that uses HTTPS, such as YouTube HLS PUSH, needs a certificate to verify the server&#8217;s identity and encrypt the data. A certificate is not needed if only HTTP is used, but the communication is not encrypted.<\/p>\n        <\/dd>\n\n        <dt>What is the difference between a private certificate and a publicly trusted certificate?<\/dt>\n        <dd>\n            <p>A publicly trusted certificate is issued by a public certificate authority that operating systems and programs trust by default. A private certificate is self-signed or issued by an internal certificate authority. Therefore, it must be separately registered as trusted in the connecting program. The main difference between the two certificates is their default trust status, not their encryption function.<\/p>\n        <\/dd>\n\n        <dt>What is the difference between a key and a certificate?<\/dt>\n        <dd>\n            <p>A private key is secret information that a server uses to prove ownership and set up TLS communication. It must not be made public. A certificate contains information such as the server name, public key, issuer, and validity period. It is presented to the connecting program. The certificate and private key must be a matching pair.<\/p>\n        <\/dd>\n\n        <dt>Can HTTPS transmission work with only a key and no certificate?<\/dt>\n        <dd>\n            <p>This is not possible in normal HTTPS communication. The server must use a certificate and its matching private key together. With only a private key, the client cannot verify the identity of the server. Therefore, it cannot operate as a normal HTTPS server.<\/p>\n        <\/dd>\n\n        <dt>Can a certificate be issued for an IP address instead of a domain address?<\/dt>\n        <dd>\n            <p>Yes. A certificate for an IP address must record the IP address in the SAN instead of a domain name. In the Python <code>cryptography<\/code> package, use <code>x509.IPAddress()<\/code> instead of <code>x509.DNSName()<\/code>. However, it is difficult to issue a publicly trusted certificate for a private IP address, and the address may change. Therefore, it is mainly used in a fixed test environment or an internal system.<\/p>\n        <\/dd>\n\n        <dt>Does Wowza Streaming Engine have certificates for every platform?<\/dt>\n        <dd>\n            <p>No. The Java trust store used by WSE does not contain the certificates of every server. It contains the root and intermediate certificates of major trusted certificate authorities. WSE checks whether the certificate presented by the server can be verified through this trust system. A self-signed certificate must be registered separately.<\/p>\n        <\/dd>\n\n        <dt>Why is only the certificate registered in Wowza, not the private key?<\/dt>\n        <dd>\n            <p>The private key must be kept by <code>PushCap<\/code>, the HTTPS receiving server. WSE is a client that connects to that server. It only needs to register the certificate presented by the server in its trust store. Do not register or send <code>key.pem<\/code> to WSE&#8217;s <code>cacerts<\/code>.<\/p>\n        <\/dd>\n\n        <dt>Does creating a certificate automatically send traffic for that domain to the test server?<\/dt>\n        <dd>\n            <p>No. A certificate only identifies and verifies the server. It does not change the network route. To send requests for <code>b.upload.youtube.com<\/code> to <code>PushCap<\/code>, map the destination to the IP address of the test server. Do this in the hosts file of the streaming device, internal DNS, or a separate proxy.<\/p>\n        <\/dd>\n\n        <dt>Can the existing registration still be used if the certificate expires or is regenerated?<\/dt>\n        <dd>\n            <p>No. A newly created certificate has a different public key and fingerprint from the existing certificate. Therefore, it must be registered again in WSE&#8217;s trust store. If the same alias already exists, delete the existing entry or use a different alias. Then restart the WSE service.<\/p>\n        <\/dd>\n\n        <dt>How can I check whether the certificate is correctly registered in Wowza?<\/dt>\n        <dd>\n            <p>Use the <code>keytool -list -cacerts<\/code> command in the JRE used by WSE. Check the alias and fingerprint of the registered certificate. To verify the integrity of the store, do not simply press Enter at the password prompt. Enter the actual <code>cacerts<\/code> password. After registration, restart the WSE service to apply the change.<\/p>\n        <\/dd>\n    <\/dl>\n<\/section>\n\n<section id=\"post-update\" class=\"post-update\">\n<h2>Update History<\/h2>\n<ol>\n  <li><time datetime=\"2025-08-27\">August 27, 2025<\/time> \u2014 <span>First published<\/span><\/li>\n  <li><time datetime=\"2026-08-18\">August 18, 2026<\/time> \u2014 <span>Revision and URL migration<\/span><\/li>\n<\/ol>\n<\/section>\n","protected":false},"excerpt":{"rendered":"<p>How to create a self-signed HTTPS HLS certificate and key with Python, register the certificate in the Java cacerts trust store used by Wowza Streaming Engine, and verify it<\/p>\n","protected":false},"author":1,"featured_media":75,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-78","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-media-ops"],"_links":{"self":[{"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/posts\/78","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/comments?post=78"}],"version-history":[{"count":2,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/posts\/78\/revisions"}],"predecessor-version":[{"id":80,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/posts\/78\/revisions\/80"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/media\/75"}],"wp:attachment":[{"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/media?parent=78"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/categories?post=78"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.eqmaker.kr\/en\/wp-json\/wp\/v2\/tags?post=78"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}