Chapter 12: Technology Stacks — LAMP, LEMP, MEAN, MERN
12.8 MEAN: Angular frontend served by Nginx
The backend (Express + MongoDB on port 5000) is exactly the same as in 12.6. Friends, only Angular takes React's place – just the build folder path is different.
बॅकएंड (Express + MongoDB पोर्ट 5000 वर) अगदी 12.6 सारखाच आहे. मित्रांनो, React च्या जागी फक्त Angular येतो – बिल्ड फोल्डरचा पाथ तेवढा वेगळा.
बैकएंड (Express + MongoDB पोर्ट 5000 पर) बिल्कुल 12.6 जैसा ही है. दोस्तों, React की जगह सिर्फ़ Angular आता है – बस बिल्ड फ़ोल्डर का पाथ अलग है.
Build the Angular app
export NG_CLI_ANALYTICS=false
sudo mkdir -p /opt/mean-frontend && sudo chown $USER:$USER /opt/mean-frontend
cd /opt/mean-frontend
npx -y @angular/cli@latest new frontend --defaults --ssr=false --skip-git --interactive=false
cd frontend
ls src/app/
Replace the root component. In Angular 20 and newer the file is src/app/app.ts (class App); in Angular 17–19 it is src/app/app.component.ts (class AppComponent — change the class name in the code below to match). This version uses signals, so it works whether or not the project uses zone.js:
cat > src/app/app.ts <<'EOF'
import { Component, OnInit, signal } from '@angular/core';
interface Note { _id: string; text: string; }
@Component({
selector: 'app-root',
standalone: true,
template: `
<div style="font-family:Arial;max-width:600px;margin:40px auto">
<h1>MEAN Notes on AWS EC2</h1>
<input #box placeholder="Write a note">
<button (click)="add(box.value); box.value = ''">Add</button>
<ul>
@for (n of notes(); track n._id) { <li>{{ n.text }}</li> }
</ul>
</div>
`,
})
export class App implements OnInit {
notes = signal<Note[]>([]);
async ngOnInit() { await this.load(); }
async load() {
const res = await fetch('/api/notes');
this.notes.set(await res.json());
}
async add(text: string) {
if (!text.trim()) return;
await fetch('/api/notes', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text }),
});
await this.load();
}
}
EOF
npx ng build # output: dist/frontend/browser/
sudo mkdir -p /var/www/mean
sudo cp -r dist/frontend/browser/* /var/www/mean/
sudo restorecon -Rv /var/www/mean 2>/dev/null # CentOS only
Angular output folder
Angular 17+ puts the production build in dist/<project-name>/browser/. Older versions used dist/<project-name>/. Check with ls dist/*.
Nginx configuration for MEAN
Identical to MERN — only the root folder changes:
sudo sed 's#/var/www/mern#/var/www/mean#' /etc/nginx/conf.d/mern.conf | sudo tee /etc/nginx/conf.d/mean.conf > /dev/null
sudo rm /etc/nginx/conf.d/mern.conf # keep only one of them for the same server_name
sudo nginx -t && sudo service nginx reload
(Angular's built assets are not in /assets/, so that caching block simply does nothing — harmless.)
Ravindra Bagale's Tip
Many students copy dist/frontend/ after the Angular build and see a blank page – in Angular 17+ the files are in dist/frontend/browser/. Run ls dist/* before copying. And don't keep both mern.conf and mean.conf for the same server_name.
Ravindra Bagale's Tip – मराठी
खूप students Angular build नंतर dist/frontend/ copy करतात आणि blank page बघतात – Angular 17+ मध्ये files dist/frontend/browser/ मध्ये असतात. Copy करण्याआधी ls dist/* चालवा. आणि एकाच server_name साठी mern.conf आणि mean.conf दोन्ही ठेवू नका.
Ravindra Bagale's Tip – हिंदी
बहुत students Angular build के बाद dist/frontend/ copy करते हैं और blank page देखते हैं – Angular 17+ में files dist/frontend/browser/ में होती हैं. Copy करने से पहले ls dist/* चलाओ. और एक ही server_name के लिए mern.conf और mean.conf दोनों मत रखो.
Lab
Chala, Angular notes app build kara aani ls dist/* ne output folder shodha. Te /var/www/mean madhe copy kara, mean.conf banva, sudo nginx -t && sudo service nginx reload kara, aani browser madhe note add hote ka te bagha.