Skip to content

Deploying a MongoDB Database

Introduction

MongoDB is a leading open-source NoSQL document database that has revolutionized how modern applications store and manage data. Developed by MongoDB Inc. and first released in 2009, MongoDB stores data in flexible, JSON-like documents (BSON format) rather than traditional rows and columns, making it exceptionally well-suited for agile development and rapidly evolving applications.

MongoDB excels at:

  • Flexible Schema: Dynamic document structure allows fields to vary between documents
  • High Performance: Optimized for both read and write operations with efficient indexing
  • Horizontal Scalability: Built-in sharding for distributing data across multiple servers
  • Rich Query Language: Powerful query and aggregation framework for complex data analysis
  • Document-Oriented: Natural mapping to object-oriented programming and JSON
  • High Availability: Replica sets provide automatic failover and data redundancy
  • Geospatial Capabilities: Native support for geospatial queries and indexing
  • Text Search: Full-text search capabilities built into the database
  • ACID Transactions: Multi-document ACID transactions for data consistency

Common use cases include content management systems, real-time analytics, IoT applications, mobile app backends, product catalogs, user profiles, and any application requiring flexible data models.

This comprehensive guide walks you through deploying MongoDB on Klutch.sh using Docker, including detailed installation steps, sample configurations, and production-ready best practices for persistent storage and security.

Prerequisites

Before you begin, ensure you have the following:


Installation and Setup

Step 1: Create Your Project Directory

First, create a new directory for your MongoDB deployment project:

Terminal window
mkdir mongodb-klutch
cd mongodb-klutch
git init

Step 2: Create the Dockerfile

Create a Dockerfile in your project root directory. This will define your MongoDB container configuration:

FROM mongo:7.0
# Set default environment variables
# These can be overridden in the Klutch.sh dashboard
ENV MONGO_INITDB_ROOT_USERNAME=admin
ENV MONGO_INITDB_ROOT_PASSWORD=adminpassword
ENV MONGO_INITDB_DATABASE=mydb
# Expose the default MongoDB port
EXPOSE 27017
# Optional: Copy initialization scripts
# JavaScript files in /docker-entrypoint-initdb.d/
# will be executed automatically on first startup
# COPY ./init.js /docker-entrypoint-initdb.d/

Note: MongoDB 7.0 is the latest stable version with improved performance, security features, and queryable encryption.

Step 3: (Optional) Create Initialization Scripts

You can create JavaScript initialization scripts that will run automatically when the database is first initialized. Create a file named init.js:

// init.js - MongoDB initialization script
// This script runs automatically on first startup
// Switch to your application database
db = db.getSiblingDB('mydb');
// Create collections with validators
db.createCollection('users', {
validator: {
$jsonSchema: {
bsonType: 'object',
required: ['username', 'email', 'createdAt'],
properties: {
username: {
bsonType: 'string',
description: 'must be a string and is required'
},
email: {
bsonType: 'string',
pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
description: 'must be a valid email and is required'
},
profile: {
bsonType: 'object',
properties: {
firstName: { bsonType: 'string' },
lastName: { bsonType: 'string' },
age: { bsonType: 'int', minimum: 0 }
}
},
createdAt: {
bsonType: 'date',
description: 'must be a date and is required'
}
}
}
}
});
// Create indexes for better query performance
db.users.createIndex({ email: 1 }, { unique: true });
db.users.createIndex({ username: 1 }, { unique: true });
db.users.createIndex({ 'profile.lastName': 1 });
// Create another collection for posts
db.createCollection('posts', {
validator: {
$jsonSchema: {
bsonType: 'object',
required: ['title', 'userId', 'createdAt'],
properties: {
title: { bsonType: 'string' },
content: { bsonType: 'string' },
userId: { bsonType: 'objectId' },
tags: { bsonType: 'array', items: { bsonType: 'string' } },
createdAt: { bsonType: 'date' },
updatedAt: { bsonType: 'date' }
}
}
}
});
// Create indexes for posts
db.posts.createIndex({ userId: 1 });
db.posts.createIndex({ tags: 1 });
db.posts.createIndex({ createdAt: -1 });
// Insert sample data (optional)
db.users.insertMany([
{
username: 'admin',
email: 'admin@example.com',
profile: {
firstName: 'Admin',
lastName: 'User',
age: 30
},
createdAt: new Date()
},
{
username: 'testuser',
email: 'test@example.com',
profile: {
firstName: 'Test',
lastName: 'User',
age: 25
},
createdAt: new Date()
}
]);
print('MongoDB initialization complete!');

If you create initialization scripts, update your Dockerfile:

FROM mongo:7.0
# Copy initialization scripts
COPY ./init.js /docker-entrypoint-initdb.d/
ENV MONGO_INITDB_ROOT_USERNAME=admin
ENV MONGO_INITDB_ROOT_PASSWORD=adminpassword
ENV MONGO_INITDB_DATABASE=mydb
EXPOSE 27017

Step 4: (Optional) Create Custom MongoDB Configuration

For production deployments, you may want to create a custom mongod.conf file. Create a file named mongod.conf:

# mongod.conf - Custom MongoDB Configuration
# Network settings
net:
port: 27017
bindIp: 0.0.0.0
# Storage settings
storage:
dbPath: /data/db
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 1
# Security settings
security:
authorization: enabled
# Logging
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
# Operation profiling
operationProfiling:
mode: slowOp
slowOpThresholdMs: 100

To use a custom configuration, update your Dockerfile:

FROM mongo:7.0
# Copy custom configuration
COPY ./mongod.conf /etc/mongod.conf
COPY ./init.js /docker-entrypoint-initdb.d/
ENV MONGO_INITDB_ROOT_USERNAME=admin
ENV MONGO_INITDB_ROOT_PASSWORD=adminpassword
ENV MONGO_INITDB_DATABASE=mydb
EXPOSE 27017
CMD ["mongod", "--config", "/etc/mongod.conf"]

Step 5: Test Locally (Optional)

Before deploying to Klutch.sh, you can test your MongoDB setup locally:

Terminal window
# Build the Docker image
docker build -t my-mongodb .
# Run the container
docker run -d \
--name mongodb-test \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=supersecret \
my-mongodb
# Wait a moment for MongoDB to start, then connect
docker exec -it mongodb-test mongosh -u admin -p supersecret
# Inside mongosh:
# show dbs
# use mydb
# show collections
# db.users.find()
# exit
# Stop and remove the test container when done
docker stop mongodb-test
docker rm mongodb-test

Step 6: Push to GitHub

Commit your Dockerfile and any configuration files to your GitHub repository:

Terminal window
git add Dockerfile init.js mongod.conf
git commit -m "Add MongoDB Dockerfile and configuration"
git remote add origin https://github.com/yourusername/mongodb-klutch.git
git push -u origin main

Connecting to MongoDB

Once deployed, you can connect to your MongoDB database from any application using a connection string. Since Klutch.sh routes TCP traffic through port 8000, use the following format:

Connection String

With Authentication:

mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin

Without Authentication (not recommended for production):

mongodb://example-app.klutch.sh:8000/mydb

Replace:

  • admin with your MongoDB admin username
  • adminpassword with your MongoDB admin password
  • example-app.klutch.sh with your actual Klutch.sh app URL
  • mydb with your database name

Example Connection Code

Node.js (using mongodb driver):

const { MongoClient } = require('mongodb');
const uri = 'mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin';
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
console.log('Connected to MongoDB');
const database = client.db('mydb');
const users = database.collection('users');
// Insert a document
const result = await users.insertOne({
username: 'newuser',
email: 'newuser@example.com',
createdAt: new Date()
});
console.log('Inserted document:', result.insertedId);
// Query documents
const allUsers = await users.find({}).toArray();
console.log('All users:', allUsers);
// Update a document
await users.updateOne(
{ username: 'newuser' },
{ $set: { 'profile.status': 'active' } }
);
// Delete a document
// await users.deleteOne({ username: 'newuser' });
} finally {
await client.close();
}
}
run().catch(console.error);

Node.js (using mongoose):

const mongoose = require('mongoose');
const uri = 'mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin';
mongoose.connect(uri)
.then(() => console.log('Connected to MongoDB with Mongoose'))
.catch(err => console.error('Connection error:', err));
// Define a schema
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
profile: {
firstName: String,
lastName: String,
age: Number
},
createdAt: { type: Date, default: Date.now }
});
const User = mongoose.model('User', userSchema);
// Create a new user
const newUser = new User({
username: 'mongooseuser',
email: 'mongoose@example.com',
profile: { firstName: 'Mongoose', lastName: 'User', age: 28 }
});
newUser.save()
.then(user => console.log('User saved:', user))
.catch(err => console.error('Save error:', err));

Python (using pymongo):

from pymongo import MongoClient
from datetime import datetime
# Connect to MongoDB
uri = "mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin"
client = MongoClient(uri)
# Access database and collection
db = client.mydb
users = db.users
# Insert a document
result = users.insert_one({
'username': 'pythonuser',
'email': 'python@example.com',
'profile': {
'firstName': 'Python',
'lastName': 'User',
'age': 27
},
'createdAt': datetime.now()
})
print(f'Inserted document ID: {result.inserted_id}')
# Query documents
all_users = list(users.find())
for user in all_users:
print(f"User: {user['username']}, Email: {user['email']}")
# Update a document
users.update_one(
{'username': 'pythonuser'},
{'$set': {'profile.status': 'active'}}
)
# Find one document
user = users.find_one({'username': 'pythonuser'})
print(f'Found user: {user}')
client.close()

Go (using mongo-go-driver):

package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
uri := "mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin"
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(context.TODO())
// Access database and collection
collection := client.Database("mydb").Collection("users")
// Insert a document
doc := bson.M{
"username": "gouser",
"email": "go@example.com",
"createdAt": time.Now(),
}
result, err := collection.InsertOne(context.TODO(), doc)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted document ID: %v\n", result.InsertedID)
// Query documents
cursor, err := collection.Find(context.TODO(), bson.M{})
if err != nil {
log.Fatal(err)
}
defer cursor.Close(context.TODO())
for cursor.Next(context.TODO()) {
var user bson.M
if err := cursor.Decode(&user); err != nil {
log.Fatal(err)
}
fmt.Printf("User: %v\n", user)
}
}

Java (using MongoDB Java Driver):

import com.mongodb.client.*;
import org.bson.Document;
import java.util.Date;
public class MongoDBConnection {
public static void main(String[] args) {
String uri = "mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin";
try (MongoClient mongoClient = MongoClients.create(uri)) {
MongoDatabase database = mongoClient.getDatabase("mydb");
MongoCollection<Document> collection = database.getCollection("users");
// Insert a document
Document user = new Document("username", "javauser")
.append("email", "java@example.com")
.append("createdAt", new Date());
collection.insertOne(user);
System.out.println("Inserted document");
// Query documents
FindIterable<Document> users = collection.find();
for (Document doc : users) {
System.out.println("User: " + doc.toJson());
}
}
}
}

Deploying to Klutch.sh

Now that your MongoDB project is ready and pushed to GitHub, follow these steps to deploy it on Klutch.sh with persistent storage.

Deployment Steps

    1. Log in to Klutch.sh

      Navigate to klutch.sh/app and sign in to your account.

    2. Create a New Project

      Go to Create Project and give your project a meaningful name (e.g., “MongoDB Database”).

    3. Create a New App

      Navigate to Create App and configure the following settings:

    4. Select Your Repository

      • Choose GitHub as your Git source
      • Select the repository containing your Dockerfile
      • Choose the branch you want to deploy (usually main or master)
    5. Configure Traffic Type

      • Traffic Type: Select TCP (MongoDB requires TCP traffic for database connections)
      • Internal Port: Set to 27017 (the default MongoDB port that your container listens on)
    6. Set Environment Variables

      Add the following environment variables for your MongoDB configuration:

      • MONGO_INITDB_ROOT_USERNAME: The MongoDB admin username (e.g., admin)
      • MONGO_INITDB_ROOT_PASSWORD: A strong password for the admin user (use a secure password generator)
      • MONGO_INITDB_DATABASE: The name of your default database (e.g., mydb)

      Security Note: Always use strong, unique passwords for production databases. These credentials will be used to authenticate connections to your MongoDB instance.

    7. Attach a Persistent Volume

      This is critical for ensuring your MongoDB data persists across deployments and restarts:

      • In the Volumes section, click “Add Volume”
      • Mount Path: Enter /data/db (this is where MongoDB stores all database files)
      • Size: Choose an appropriate size based on your expected data volume (e.g., 10GB, 20GB, 50GB)

      Important: MongoDB requires persistent storage to maintain your data between container restarts. Without a volume, all data will be lost when the container restarts.

    8. Configure Additional Settings

      • Region: Select the region closest to your users for optimal latency
      • Compute Resources: Choose CPU and memory based on your workload (minimum 512MB RAM recommended, 1GB+ for production workloads)
      • Instances: Start with 1 instance (single instance deployment for simplicity)
    9. Deploy Your Database

      Click “Create” to start the deployment. Klutch.sh will:

      • Automatically detect your Dockerfile in the repository root
      • Build the Docker image
      • Attach the persistent volume
      • Start your MongoDB container
      • Execute any initialization scripts in /docker-entrypoint-initdb.d/
      • Assign a URL for external connections
    10. Access Your Database

      Once deployment is complete, you’ll receive a URL like example-app.klutch.sh. You can connect to your MongoDB database using this URL on port 8000:

      mongodb://admin:adminpassword@example-app.klutch.sh:8000/mydb?authSource=admin

Production Best Practices

Security Recommendations

  • Enable Authentication: Always enable authentication in production using MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD
  • Strong Passwords: Use complex, randomly generated passwords
  • Least Privilege: Create application-specific users with only the permissions they need
  • Network Security: MongoDB is accessible only through Klutch.sh’s secure network by default
  • Regular Updates: Keep your MongoDB version up to date with security patches
  • Encryption at Rest: For sensitive data, consider enabling encryption at rest
  • Connection String Security: Never hardcode connection strings in your application code

Performance Optimization

  • Indexing: Create appropriate indexes for your query patterns
  • WiredTiger Cache: Allocate 50-60% of available RAM to WiredTiger cache (default behavior)
  • Connection Pooling: Use connection pooling in your application to manage database connections efficiently
  • Query Optimization: Use explain() to analyze and optimize slow queries
  • Proper Data Modeling: Design your document structure based on your access patterns
  • Aggregation Pipeline: Use aggregation pipelines for complex data transformations instead of client-side processing

Data Modeling Best Practices

Embedding vs. Referencing:

// Embedded documents (good for 1-to-few relationships)
{
_id: ObjectId("..."),
username: "john",
addresses: [
{ street: "123 Main St", city: "New York" },
{ street: "456 Oak Ave", city: "Boston" }
]
}
// Referenced documents (good for 1-to-many or many-to-many)
// Users collection
{ _id: ObjectId("user1"), username: "john" }
// Posts collection
{ _id: ObjectId("post1"), userId: ObjectId("user1"), title: "My Post" }

Backup Strategy

Implement a comprehensive backup strategy:

Terminal window
# Backup using mongodump
mongodump --uri="mongodb://admin:password@example-app.klutch.sh:8000/mydb?authSource=admin" --out=/backup
# Restore using mongorestore
mongorestore --uri="mongodb://admin:password@example-app.klutch.sh:8000/?authSource=admin" /backup

Consider:

  • Automated daily backups
  • Multiple retention periods (daily, weekly, monthly)
  • Offsite backup storage
  • Regular restore testing
  • Point-in-time recovery using oplog

Monitoring

Monitor your MongoDB deployment for:

  • Query performance and slow queries (use profiling)
  • Connection count and connection pool utilization
  • Disk usage and I/O patterns
  • CPU and memory utilization
  • WiredTiger cache efficiency
  • Replication lag (if using replica sets)
  • Collection and index sizes

Use MongoDB’s built-in profiling:

// Enable profiling for slow operations (>100ms)
db.setProfilingLevel(1, { slowms: 100 });
// View slow queries
db.system.profile.find().sort({ ts: -1 }).limit(10);

Troubleshooting

Cannot Connect to Database

  • Verify you’re using the correct connection string with port 8000
  • Ensure authentication credentials (username, password) are correct
  • Check that authSource=admin is included in the connection string
  • Verify that the internal port is set to 27017 in your app configuration
  • Ensure TCP traffic is selected

Authentication Failed

  • Verify MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD are set correctly
  • Ensure you’re connecting to the correct database with proper authSource
  • Check that initialization completed successfully on first startup
  • Try connecting with the mongosh CLI first to verify credentials

Database Not Persisting Data

  • Verify the persistent volume is correctly attached at /data/db
  • Check that the volume has sufficient space allocated
  • Ensure the container has write permissions to the volume

Performance Issues

  • Review slow query log using database profiling
  • Ensure appropriate indexes exist for your query patterns
  • Check if WiredTiger cache is properly sized
  • Monitor memory usage and adjust compute resources if needed
  • Consider sharding for very large datasets

Out of Disk Space

  • Check volume usage and increase size if needed
  • Run db.stats() to see database size
  • Use db.collection.stats() to identify large collections
  • Consider data archiving or TTL indexes for time-series data
  • Compact collections if fragmented

Connection Pool Exhaustion

  • Increase connection pool size in your application
  • Check for connection leaks (ensure connections are properly closed)
  • Monitor active connections: db.serverStatus().connections
  • Consider increasing MongoDB’s maxIncomingConnections setting

Advanced MongoDB Features

Aggregation Framework

MongoDB’s aggregation framework provides powerful data processing:

// Example: Group posts by user and count
db.posts.aggregate([
{ $group: {
_id: "$userId",
postCount: { $sum: 1 },
avgViews: { $avg: "$views" }
}},
{ $sort: { postCount: -1 } },
{ $limit: 10 }
]);

Change Streams

Watch for real-time changes in your collections:

const changeStream = db.users.watch();
changeStream.on('change', (change) => {
console.log('Change detected:', change);
});

Create text indexes for full-text search:

// Create text index
db.posts.createIndex({ title: "text", content: "text" });
// Search
db.posts.find({ $text: { $search: "mongodb tutorial" } });

Geospatial Queries

Store and query location data:

// Create geospatial index
db.locations.createIndex({ coordinates: "2dsphere" });
// Find locations near a point
db.locations.find({
coordinates: {
$near: {
$geometry: { type: "Point", coordinates: [-73.9667, 40.78] },
$maxDistance: 1000 // meters
}
}
});

Time-Series Collections (MongoDB 5.0+)

Optimized for time-series data:

db.createCollection("sensor_data", {
timeseries: {
timeField: "timestamp",
metaField: "sensor_id",
granularity: "minutes"
}
});

Additional Resources


Conclusion

Deploying MongoDB to Klutch.sh with Docker provides a flexible, scalable NoSQL database solution perfect for modern applications requiring dynamic schemas and high performance. By following this guide, you’ve set up a production-ready MongoDB database with proper authentication, persistent storage, and best practices for security and performance. Your MongoDB instance is now ready to power your applications with reliable, document-oriented data storage.