Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
01 Aug 2025 · 5 min read ·Article 54 / 110
Go

54. Using a Self-signed Certificate

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

54. Using a Self-signed Certificate: A Complete Guide for Software Engineers

Security is a fundamental aspect of software development, especially when our applications communicate over a network. From internal APIs and microservice-to-microservice communication to local development, using the HTTPS (Hypertext Transfer Protocol Secure) protocol has become the standard rather than the exception. However, we often run into challenges around SSL certificates, whether it’s cost, management overhead, or simply running local experiments. This is where the self-signed certificate plays a crucial role.

In this article, I’ll take a comprehensive look at how to create and use self-signed certificates, as well as understand their risks and benefits. I’ll also include practical code, scenario simulations, and diagrams to help you, as a software engineer, make the right decisions when implementing them.


What Is a Self-signed Certificate?

A self-signed certificate is an SSL/TLS certificate that is not signed by a public Certificate Authority (CA), but instead signed directly by the entity that created it (for example, your own server).

In a production environment, a valid certificate is usually issued by an official CA such as Let’s Encrypt, DigiCert, or Comodo. However, in staging or local environments, engineers are often fine using a self-signed certificate to test HTTPS-based features.

When Should You Use a Self-signed Certificate?

Use CaseSuitable for Self-signed?
Development Environment✅ Yes
Internal Staging/Testing✅ Yes, with caveats
Production/Public❌ Strongly discouraged
Internal microservice-to-microservice communication (private network)✅, with extra security measures

How to Create a Self-signed Certificate with OpenSSL

The most common tool for generating a self-signed certificate is OpenSSL, which is widely available on modern operating systems.

Step-by-step Certificate Creation

  1. Generate a Private Key
bash
1openssl genrsa -out key.pem 2048
  1. Generate a Certificate Signing Request (CSR)
bash
1openssl req -new -key key.pem -out csr.pem

During this process, you’ll be asked to fill in some information, such as Country Name, State, and Common Name (enter the domain/server name you want to secure, for example localhost).

  1. Generate the Self-signed Certificate
bash
1openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pem

Now you have two important files:

  • cert.pem : the public certificate
  • key.pem : the private key (keep it secret!)

File Structure

FilePurpose
cert.pemPublic certificate
key.pemPrivate key
csr.pem(optional) CSR

Implementation Walkthrough in a Node.js Application

Let’s walk through how a self-signed certificate is used in a simple Node.js HTTPS server.

Project Structure

text
1/my-https-app
2├── cert.pem
3├── key.pem
4└── server.js

Server Code (server.js)

javascript
 1const https = require('https');
 2const fs = require('fs');
 3const path = require('path');
 4
 5const options = {
 6  key: fs.readFileSync(path.join(__dirname, 'key.pem')),
 7  cert: fs.readFileSync(path.join(__dirname, 'cert.pem'))
 8};
 9
10https.createServer(options, (req, res) => {
11  res.writeHead(200);
12  res.end('Hello, HTTPS with Self-signed Certificate!');
13}).listen(8443, () => {
14  console.log('Server running at https://localhost:8443');
15});

Testing the Setup

Try accessing https://localhost:8443 from your browser. The browser will typically warn you that the certificate is “untrusted” — this is normal, because your certificate isn’t recognized by a public authority.

Tip: To bypass this in development, go ahead and “accept the risk”.


How Does a Browser/Client Validate a Certificate?

Let’s look at the flow diagram of how a TLS client validates a self-signed certificate:

MERMAID
flowchart TD
    A[Client Request ke HTTPS Server] --> B[Server mengirimkan Public Certificate]
    B --> C{Trusted CA?}
    C --Tidak--> D[Tampilkan Warning atau Tolak Koneksi]
    C --Ya--> E[Lanjutkan SSL Handshake]
    D --> F[User Bisa Lanjut (Manual)]

With a self-signed certificate, the validation process stops at “No”, so the browser/client will either reject the connection or display a warning.


Risks & Best Practices for Using Self-signed Certificates

Risks

  1. Not Trusted by Default: The client will show a security warning every time it connects.
  2. Vulnerable to MITM when used on a public network: Because anyone can create a similar certificate.
  3. Not suitable for production/public websites: SSL Labs and search engines will consider the connection insecure.

Best Practices

  • Limit usage to internal/development environments.
  • Never commit the key.pem file to version control.
  • Manage certificate expiry — keep an eye on the validity period to avoid sudden errors.
  • You can add the self-signed certificate to the trusted store on the client if needed (for example, for automated testing with curl, Postman, or a CI/CD pipeline).

How to Automate It with Docker Compose

Simulation: Deploy an HTTPS-based service with Docker Compose and a self-signed certificate.

Example docker-compose.yml:

yaml
 1version: "3"
 2services:
 3  web:
 4    image: node:18
 5    volumes:
 6      - ./server.js:/app/server.js
 7      - ./cert.pem:/app/cert.pem
 8      - ./key.pem:/app/key.pem
 9    working_dir: /app
10    command: ["node", "server.js"]
11    ports:
12      - "8443:8443"

How to Add It to a Local CA (Testing Automation)

For example, on a Linux machine, add the self-signed cert to the trusted CA store:

bash
1sudo cp cert.pem /usr/local/share/ca-certificates/my-app-cert.crt
2sudo update-ca-certificates

Note: Do this only on development/testing machines, never on a production user’s laptop.


Conclusion

A self-signed certificate is a quick and practical solution for development environments or internal needs, free from the cost and management burden of an external CA—as long as it’s used appropriately. As an engineer, understand the validation flow, the security risks, and how to mitigate them.

For production, always use an official CA so users can trust the application you build. But for prototyping and testing, a self-signed certificate clearly saves a lot of time!


Through this article, I hope you now feel more confident using self-signed certificates as an integral part of your modern application development workflow. Happy experimenting, and always prioritize security!


References and Additional Reading

Related Articles

💬 Comments