54. Using a Self-signed Certificate
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 Case | Suitable 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
- Generate a Private Key
1openssl genrsa -out key.pem 2048- Generate a Certificate Signing Request (CSR)
1openssl req -new -key key.pem -out csr.pemDuring 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).
- Generate the Self-signed Certificate
1openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pemNow you have two important files:
cert.pem: the public certificatekey.pem: the private key (keep it secret!)
File Structure
| File | Purpose |
|---|---|
| cert.pem | Public certificate |
| key.pem | Private 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
1/my-https-app
2├── cert.pem
3├── key.pem
4└── server.jsServer Code (server.js)
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:
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
- Not Trusted by Default: The client will show a security warning every time it connects.
- Vulnerable to MITM when used on a public network: Because anyone can create a similar certificate.
- 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:
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:
1sudo cp cert.pem /usr/local/share/ca-certificates/my-app-cert.crt
2sudo update-ca-certificatesNote: 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