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.
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.)