TL;DR: A step-by-step walkthrough from an empty folder to a live HTTPS URL: a small Express app, a Dockerfile and a .dockerignore, a local test, a push to GitHub, the deploy itself, environment variables, an optional $1 managed database, and the checks that tell you it worked. No card and no DevOps background needed.
This hands-on guide walks you through deploying your first Docker container for free. We'll cover project setup, Dockerfile creation, environment configuration, and the actual deployment process with real code examples.
Prerequisites
- A GitHub account
- Basic familiarity with the command line
- A simple application (we'll use a Node.js example)
Step 1: Prepare Your Application
Let's create a simple Express.js application. Create these files in your project:
{ "name": "my-free-container", "version": "1.0.0", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "express": "^4.18.2" } } const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000; app.get('/', (req, res) => { res.json({ status: 'running', message: 'Hello from my free container!', timestamp: new Date().toISOString() }); }); app.get('/health', (req, res) => { res.status(200).send('OK'); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); Step 2: Create a Dockerfile
Add a Dockerfile to your project root:
# Use official Node.js LTS image FROM node:22-alpine # Set working directory WORKDIR /app # Copy package files first (for better caching) COPY package*.json ./ # Install dependencies RUN npm ci --only=production # Copy application code COPY . . # Expose the port your app runs on EXPOSE 3000 # Start the application CMD ["npm", "start"] Dockerfile Best Practices
- Use Alpine images — Smaller size means faster builds
- Copy package.json first — Enables Docker layer caching
- Use npm ci — Faster and more reliable than npm install
- Don't run as root — Add a non-root user for production
Step 3: Add a .dockerignore File
Create .dockerignore to exclude unnecessary files:
node_modules npm-debug.log .git .gitignore .env *.md .DS_Store Step 4: Test Locally (Optional)
Before deploying, verify your container works locally:
# Build the image docker build -t my-app . # Run the container docker run -p 3000:3000 my-app # Test it curl http://localhost:3000 Step 5: Push to GitHub
Initialize a git repository and push your code:
git init git add . git commit -m "Initial commit with Dockerfile" git remote add origin https://github.com/yourusername/my-app.git git push -u origin main Step 6: Deploy to SnapDeploy
Now deploy your containerized application:
- Create account — Go to snapdeploy.dev and sign up (no credit card)
- New Container — Click "New Container" in the dashboard
- Connect GitHub — Authorize access and select your repository
- Configure — Set container name (becomes your-app.containers.snapdeploy.app)
- Deploy — Click Deploy and watch the build logs
Step 7: Configure Environment Variables
If your app needs environment variables, add them in the dashboard:
# Example environment variables NODE_ENV=production DATABASE_URL=postgresql://user:pass@host:5432/db API_KEY=your-secret-key Access them in your code with process.env.VARIABLE_NAME.
Step 7b (Optional): Add a Managed Database for $1
Your free container is stateless — data inside the container resets on every deploy. For persistent data, add a managed database. You have two paths:
- Test first with the DB Sprint Pack — $1 for 12 hours. Pick any of six engines (PostgreSQL 16, MySQL 8, MariaDB 11, MongoDB 7, Redis 7, RabbitMQ 3) at full Mini-tier capacity. Persistent EFS storage, daily backups, full privileged access. Convert to monthly anytime during the 12-hour window or the 24-hour grace afterward — same EFS volume re-attaches, zero data migration.
- Or go straight to a monthly subscription: Mini from $29/mo (SQL), $12/mo (Redis), $14/mo (RabbitMQ). Auto-injected connection strings.
Once provisioned, SnapDeploy injects the database connection string into your container as an environment variable (DATABASE_URL for SQL, REDIS_URL for Redis, etc.) — your app reads it the same way as the example above.
Read the DB Sprint Pack guide →
Step 8: Verify Deployment
Once deployed, test your live container:
# Test the root endpoint curl https://your-app.containers.snapdeploy.app # Expected response: { "status": "running", "message": "Hello from my free container!", "timestamp": "2026-01-06T10:30:00.000Z" } Troubleshooting Common Issues
Ensure package-lock.json is committed. Run npm install locally first.
Check that your app listens on the PORT environment variable, not a hardcoded port.
Check the logs in the dashboard. Common cause: missing environment variables or database connection failures.
⚡ Need it online 24/7? Skip the cold starts.
Your free container sleeps when idle and wakes when a visitor opens it — perfect for side projects. But for a client demo, an interview review, or a weekend launch that has to stay up, drop a Sprint Pack on it: $1 / ₹99 for 24 hours of unlimited deploys plus Always-On. One-time, no subscription, no auto-renewal.
Next Steps
- Configure environment variables for secrets and config
- Add a custom domain to your container
- Set up monitoring to track container health
You now have a containerized application running for free. Free deploy includes auto-sleep when idle and auto-wake on visits — your container is there when someone opens it. For 24/7 uptime, add Always-On starting at $12/month.

