A modern, responsive portfolio website built with Next.js, React, and TypeScript. Features dynamic image galleries, multilingual support, and an integrated contact form with EmailJS.
- Features
- Live Website
- Deployment Architecture
- Setup Instructions
- Docker Deployment
- Project Structure
- Technologies Used
- Contact Form Features
- Image Optimization
- API Routes
- Security Notes
- Dynamic Image Gallery: Random background image rotation from organized asset folders
- API Integration: Next.js API routes for image management and metadata
- Multilingual Support: English and Turkish translations with dynamic content
- Contact Form: EmailJS integration with user metadata collection
- Responsive Design: Modern UI with custom CSS modules
- Image Optimization: Automated image compression and resizing
- Fast Performance: Built with Next.js for optimal loading speeds and SEO
Current Deployment: https://melihemre.dev
Infrastructure: AWS EC2 with Docker containerization and nginx reverse proxy
This portfolio website is deployed on AWS EC2 using a modern containerized infrastructure:
- Container: Docker with nginx for static file serving
- Reverse Proxy: jwilder/nginx-proxy for automatic domain routing
- SSL: Automatic Let's Encrypt certificate management
- CI/CD: GitHub Actions for automated deployment
- Domain: Custom domain with Cloudflare DNS management
Note: Previously deployed on GitHub Pages but migrated to AWS EC2 due to performance issues. GitHub Pages had significant loading delays (up to 60 seconds) and was too slow for optimal user experience. The current AWS infrastructure provides faster loading times and better reliability.
git clone https://github.com/melihemreguler/melihemreguler.github.io.git
cd melihemreguler.github.io
npm install
Create a .env.local
file in the root directory:
# Copy the example file
cp .env.example .env.local
Fill in your EmailJS credentials in the .env.local
file:
NEXT_PUBLIC_EMAILJS_SERVICE_ID=your_service_id_here
NEXT_PUBLIC_EMAILJS_TEMPLATE_ID=your_template_id_here
NEXT_PUBLIC_EMAILJS_PUBLIC_KEY=your_public_key_here
- Create an account at EmailJS.com
- Add your email service (Gmail, Outlook, etc.)
- Create an email template
- Get your Service ID, Template ID, and Public Key
- Update the
.env
file with these values
npm run dev
The development server will start on http://localhost:3000
(or next available port).
npm run build
npm run start
The website is containerized using Docker with a multi-stage build process optimized for Next.js:
# Build the Docker image with build arguments
docker build \
--build-arg NEXT_PUBLIC_EMAILJS_SERVICE_ID=your_service_id \
--build-arg NEXT_PUBLIC_EMAILJS_TEMPLATE_ID=your_template_id \
--build-arg NEXT_PUBLIC_EMAILJS_PUBLIC_KEY=your_public_key \
-t portfolio:latest .
# Run locally
docker run -p 3000:80 portfolio:latest
The production deployment uses Docker Compose with nginx-proxy:
# Deploy to production (on AWS EC2)
docker compose up -d portfolio
Deployment Features:
- Multi-stage Docker build (Node.js build + nginx serving)
- Automatic SSL certificate management
- Health checks and monitoring
- Automated cleanup and resource management
- Comprehensive deployment validation
src/
├── components/
│ ├── IntroAnimation.tsx # Animated intro component
│ └── TypewriterText.tsx # Typewriter animation effect
├── data/
│ ├── experience.json # Work experience data
│ ├── projects.json # Project portfolio data
│ ├── techStack.json # Technology stack information
│ ├── translations.json # Multilingual content
│ └── socialLinks.json # Social media links
├── pages/
│ ├── api/
│ │ └── images.ts # API route for image management
│ ├── _app.tsx # Next.js app configuration
│ ├── _document.tsx # Custom document structure
│ └── index.tsx # Main homepage
├── styles/
│ ├── globals.css # Global styles
│ ├── Home.module.css # Homepage specific styles
│ ├── IntroAnimation.module.css # Intro animation styles
│ └── CodeTypingAnimation.module.css # Code typing styles
├── utils/
│ ├── imageUtils.ts # Image processing utilities
│ ├── introUtils.ts # Intro animation utilities
│ ├── languageUtils.ts # Language switching utilities
│ └── translationUtils.ts # Translation interpolation
└── views/
├── AboutView.tsx # About section component
├── ContactView.tsx # Contact form with EmailJS
├── ExperienceView.tsx # Work experience section
├── FooterView.tsx # Footer with dynamic year
├── HeroView.tsx # Hero section with background images
├── ProjectsView.tsx # Projects showcase
└── TechStackView.tsx # Technology stack display
# Configuration & Deployment
├── next.config.ts # Next.js configuration
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Production deployment config
├── nginx.conf # nginx configuration
└── .github/workflows/deploy.yml # CI/CD pipeline
- Next.js 15 with TypeScript and React 19
- CSS Modules for component-scoped styling
- Framer Motion for animations and transitions
- EmailJS for contact form functionality
- Custom API Routes for dynamic image management
- Docker for containerization
- nginx for static file serving
- AWS EC2 for hosting infrastructure
- GitHub Actions for CI/CD automation
- ImageMagick for image optimization
- Real-time form validation
- Loading states and success/error messages
- Bilingual support (English/Turkish)
- User metadata collection (IP, browser info, timezone)
- Direct email sending via EmailJS
- Responsive design with animations
- Environment variable protection for API keys
The project includes automated image optimization for better performance:
# Optimize images in public/assets directory (using ImageMagick)
cd public/assets
find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" \) -exec mogrify -resize '1200x1200>' -quality 85 {} \;
find . -type f -iname "*.png" -exec mogrify -resize '1200x1200>' {} \;
Optimization Results:
- Original size: ~82MB → Optimized: ~7.3MB (91% reduction)
- Maximum dimensions: 1200x1200 pixels
- JPEG quality: 85% (optimal for web)
- Supports JPG, PNG, WebP formats
The project uses Next.js API routes for dynamic functionality:
Returns organized image folder structure from public/assets
:
{
"success": true,
"folders": [
{
"path": "assets/graduation",
"images": ["IMG-20250701-WA0001.jpg", "..."]
}
],
"totalFolders": 8,
"totalImages": 38
}
Features:
- Recursive directory scanning
- Web-format filtering (JPG, PNG, WebP, etc.)
- Error handling and logging
- CORS headers for development
- Environment variables are used to protect EmailJS credentials
.env.local
file is excluded from version control- GitHub Actions secrets ensure secure deployment
- No sensitive information is exposed in the public repository
- Docker multi-stage builds for optimized production images
- nginx security headers and proper configuration
- CORS headers configured for API routes
- Image optimization reduces server load and improves performance
The nginx configuration includes advanced caching mechanisms for optimal performance:
- Images: 30-day cache with
max-age=2592000
- CSS/JS: 7-day cache with
max-age=604800
- Fonts: 1-year cache with
immutable
directive - JSON/XML: 1-day cache with
max-age=86400
- Configured proxy cache path:
/var/cache/nginx
- Cache zone:
static_cache
with 10MB memory and 1GB disk space - Cache validity: 10 minutes for successful responses, 1 minute for 404s
- Background cache updates and stale content serving for high availability
Cache-Control
headers for browser cachingVary: Accept-Encoding
for proper compression handlingETag
support for efficient cache validation- Access logs disabled for static assets to reduce I/O
- Reduced server load by serving cached content
- Faster page load times for returning visitors
- Improved bandwidth efficiency
- Better user experience with instant static content delivery
- Persistent nginx cache volume for container restarts
- Proper cache directory permissions and ownership
For production cache management, use the production-tools.sh
script that's automatically downloaded during deployment:
# Download the tools (done automatically during deploy)
curl -O https://raw.githubusercontent.com/melihemreguler/melihemreguler.github.io/main/production-tools.sh
chmod +x production-tools.sh
# Available commands
./production-tools.sh clear # Clear nginx cache
./production-tools.sh stats # Show cache statistics
./production-tools.sh restart # Reload nginx configuration
./production-tools.sh performance # Check performance metrics
./production-tools.sh bundles # Analyze bundle sizes
./production-tools.sh report # Generate full performance report
./production-tools.sh logs # Show container logs
# Clear cache remotely
curl -s https://raw.githubusercontent.com/melihemreguler/melihemreguler.github.io/main/production-tools.sh | bash -s clear
# Get performance report
curl -s https://raw.githubusercontent.com/melihemreguler/melihemreguler.github.io/main/production-tools.sh | bash -s report
# Quick performance check
curl -s https://raw.githubusercontent.com/melihemreguler/melihemreguler.github.io/main/production-tools.sh | bash -s performance
If experiencing high LCP (Largest Contentful Paint) times:
- Clear cache:
./production-tools.sh clear
- Check compression:
./production-tools.sh performance
- Analyze bundles:
./production-tools.sh bundles
- Restart nginx:
./production-tools.sh restart
The deployment process includes automatic performance analysis that checks:
- Cache directory setup
- Compression enablement
- Static file caching
- Bundle sizes
- Image optimization