A simple, production-ready "Hello World" web application designed for deployment via Coolify. This project demonstrates best practices for Docker Compose, environment configuration, and Coolify integration.
- Minimal Node.js/Express Application - Lightweight and fast
- Health Check Endpoint -
/healthendpoint for monitoring - Beautiful UI - Responsive design with gradient background
- Environment-Based Configuration - Customizable via environment variables
- Security Best Practices - Runs as non-root user, no exposed ports in production
- Development/Production Separation - Override file for local development
hello-world-coolify/
├── src/
│ └── server.js # Main application server
├── public/ # Static assets (if needed)
├── docker-compose.yaml # Production compose (for Coolify)
├── docker-compose.override.yaml.example # Local dev template
├── Dockerfile # Production Docker image
├── .dockerignore # Docker build exclusions
├── .gitignore # Git exclusions
├── .env.example # Environment variable template
├── package.json # Node.js dependencies
└── README.md # This file
-
Clone the repository (or copy this folder)
-
Install dependencies:
npm install
-
Create local environment file:
cp .env.example .env
-
Create Docker override file:
cp docker-compose.override.yaml.example docker-compose.override.yaml
-
Start the application:
# Option A: Run directly with Node.js npm start # Option B: Run with Docker Compose docker-compose up
-
Access the application:
- Main page: http://localhost:3000
- Health check: http://localhost:3000/health
- API info: http://localhost:3000/api/info
-
Push to Git Repository:
git add . git commit -m "Initial commit: Hello World Coolify app" git push origin main
-
Create New Resource in Coolify:
- Go to your Coolify dashboard
- Click "New Resource"
- Select "Public Repository" or connect via GitHub App
- Enter your repository URL
-
Configure Build Settings:
- Build Pack: Docker Compose
- Compose File Location:
/docker-compose.yaml(or path relative to repo root) - Base Directory:
apps/common/hello-world-coolify(if in a monorepo)
-
Set Environment Variables in Coolify UI:
PORT=3000 NODE_ENV=production HELLO_MESSAGE=Hello from Coolify! -
Assign Domain:
- In Coolify UI, go to your service
- Set domain (e.g.,
https://hello.example.com) - If app listens on port 3000, specify:
https://hello.example.com:3000 - Coolify exposes it as standard
https://hello.example.com
-
Deploy:
- Click "Deploy" button
- Monitor build logs
- Access your application at the assigned domain
| Variable | Description | Default | Required |
|---|---|---|---|
PORT |
Application port | 3000 |
No |
NODE_ENV |
Environment mode | production |
No |
HELLO_MESSAGE |
Custom greeting message | Hello World! |
No |
DOCKER_RESTART_POLICY |
Container restart policy | unless-stopped |
No |
DOCKER_WEB_HEALTHCHECK_TEST |
Health check command | Node.js HTTP check | No |
Main application page with a beautiful UI displaying:
- Custom hello message
- Environment information
- Node version
- Port number
- Server uptime
Response: HTML page
Health check endpoint for monitoring and Coolify health checks.
Response:
{
"status": "healthy",
"timestamp": "2025-01-11T10:30:00.000Z",
"uptime": 3600.5,
"environment": "production"
}JSON API endpoint returning application information.
Response:
{
"message": "Hello from Coolify!",
"environment": "production",
"nodeVersion": "v20.11.0",
"port": 3000,
"uptime": 3600.5,
"timestamp": "2025-01-11T10:30:00.000Z"
}npm run devUses Node.js built-in watch mode (Node 20+) to automatically restart on file changes.
# Start with volume mounting for live code updates
docker-compose up
# Rebuild after dependency changes
docker-compose up --build
# Stop containers
docker-compose downThe docker-compose.override.yaml file:
- Exposes port 3000 to localhost
- Mounts source code for live updates
- Disables restart policy
- Sets development environment
- Non-root user: Container runs as
appuser(UID 1000) - No exposed ports: Coolify handles routing via Traefik proxy
- Environment-based secrets: No hard-coded credentials
The application includes Docker health checks:
- Interval: Every 60 seconds
- Timeout: 3 seconds
- Start period: 5 seconds
- Retries: 3 attempts before marking unhealthy
Health check hits /health endpoint and verifies 200 response.
Minimal footprint:
- Base Image:
node:20-alpine(~40MB compressed) - Application: ~5MB
- Memory: ~50MB runtime
- CPU: Minimal (single-threaded Express)
Default: unless-stopped
- Automatically restarts on failure
- Survives server reboots
- Stops only on manual intervention
Option 1: Environment Variable
# Coolify UI
HELLO_MESSAGE=Welcome to My App!
# Local .env
export HELLO_MESSAGE=Welcome to My App!Option 2: Modify Source Code
Edit src/server.js:
const HELLO_MESSAGE = process.env.HELLO_MESSAGE || 'Your Custom Message';Place files in public/ directory. They're automatically served:
public/favicon.ico→ Available at/favicon.icopublic/images/logo.png→ Available at/images/logo.pngpublic/styles.css→ Available at/styles.css
Edit src/server.js:
app.get('/api/hello/:name', (req, res) => {
res.json({ message: `Hello, ${req.params.name}!` });
});# Find process using port 3000
lsof -ti:3000
# Kill the process
kill -9 $(lsof -ti:3000)
# Or change port in .env
export PORT=3001-
Verify app listens on correct port:
app.listen(PORT, '0.0.0.0', ...) // Not 'localhost'
-
Check Coolify domain configuration:
- Ensure port matches:
https://domain.com:3000tells Coolify to route to port 3000
- Ensure port matches:
-
Check logs in Coolify UI for startup errors
- Verify domain assignment in Coolify UI
- Check environment variables are set correctly
- Ensure no port exposure in
docker-compose.yaml(should have noports:section) - Review Traefik labels (Coolify adds these automatically)
- Check Dockerfile syntax
- Verify dependencies in
package.json - Review build logs in Coolify UI
- Test locally:
docker build -t hello-test . docker run -p 3000:3000 hello-test
✅ Single docker-compose.yaml - Even for single-service app
✅ No port exposure in production - Let Coolify handle routing
✅ Environment variables - Configurable via .env
✅ Override file for dev - Keeps production config clean
✅ Health checks included - Monitor application health
✅ Non-root user - Security best practice
✅ Production defaults - Override in dev, not prod
✅ Documentation - Comprehensive README and examples
- Coolify Documentation
- Docker Compose Specification
- Express.js Documentation
- Node.js Docker Best Practices
MIT
For Coolify-specific issues, consult the Coolify documentation or community forum.
For application issues, review the troubleshooting section above or check application logs.