Turning a fresh Alibaba Cloud ECS instance from "I can SSH in" to "public visitors can access my site reliably" involves three common stumbling blocks: network access (security groups + firewall rules), service coordination (Apache – PHP – MySQL request pipeline), and permission/version mismatches (directory ownership, PHP extensions, MySQL authentication). This guide first clarifies the LAMP architecture with diagrams, then walks through security group configuration, environment installation with verification steps, Apache/MySQL/PHP installation with key configurations, and finally a complete Discuz deployment plus source-compile installation workflow (including cleanup, dependency preparation, service auto-start, and common troubleshooting scenarios). By the end, you'll have a traditional Web stack running on the cloud from 0 to 1.
Why LAMP Still Matters in 2025
LAMP (Linux + Apache + MySQL + PHP) is often dismissed as "legacy" compared to containerized microservices, but for small to mid-sized content sites, CMS platforms (WordPress, Discuz, Drupal), and many SaaS backends, LAMP remains the most cost-effective, well-documented, and maintenance-friendly solution.
Key advantages:
- Mature ecosystem: Decades of plugins, tutorials, stack overflow answers
- Shared hosting compatibility: Easy to migrate from/to managed hosting
- Predictable performance: No orchestration overhead, direct request path
- Lower barrier: One server, three services — easier to reason about than Kubernetes
When NOT to use LAMP:
- High concurrency APIs (consider Nginx + Node/Go/Rust)
- Microservices architecture (use Docker + orchestration)
- Real-time features (WebSocket-heavy apps prefer event-driven stacks)
LAMP Architecture: The Request Flow
Understanding how a request travels through the stack is critical for debugging.
The four-layer model
User → Apache (Web Server)
Browser sends HTTP request to port 80/443. Apache parses the URL and determines which file to serve.Apache → PHP (Application Runtime)
If the requested file is.php, Apache invokes PHP viamod_phpor FastCGI to execute the script.PHP → MySQL (Database)
PHP script queries MySQL viamysqli/PDOextensions to fetch/store data.MySQL → PHP → Apache → User
Data flows back through the same pipeline, rendered as HTML and returned to the browser.
Critical interfaces to verify:
- Apache can read
.phpfiles (file permissions) - Apache can invoke PHP (module loaded)
- PHP can connect to MySQL (extension installed, credentials correct)
Part I: Alibaba Cloud ECS Networking Setup
Before installing any software, you must open ports at two layers: cloud security group (virtual firewall) and OS-level firewall (iptables/firewalld).
1. Assigning a Public IP
In the ECS console:
- Select your instance → Networking → Public IP.
- If no public IP is assigned, bind one from your available IP pool.
- Record the IP (e.g.,
8.134.207.88) for testing later.
2. Configuring Security Group Rules
Navigate to Security Groups → Manage Rules → Inbound. Add:
| Protocol | Port | Source CIDR | Purpose |
|---|---|---|---|
| TCP | 22 | 0.0.0.0/0 | SSH login |
| TCP | 80 | 0.0.0.0/0 | HTTP traffic |
| TCP | 443 | 0.0.0.0/0 | HTTPS traffic |
| TCP | 3306 | Your IP only | MySQL remote access (optional, risky if opened to all) |
Security tip: Never expose MySQL (3306) to
0.0.0.0/0 in production. Use SSH tunneling instead:
1
ssh -L 3306:localhost:3306 user@8.134.207.88
3. OS-level Firewall (iptables/firewalld)
On CentOS/RHEL (firewalld): 1
2
3sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
On Ubuntu/Debian (ufw): 1
2
3
4sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Verification: 1
curl http://YOUR_PUBLIC_IP
Part II: Installing LAMP Components (Ubuntu Example)
Prerequisites: Disable conflicting services
Before installing, stop any existing web servers or databases:
1
2
3
4
5
6# Check for running services
sudo systemctl status apache2 httpd nginx mysql mariadb
# Stop if found
sudo systemctl stop apache2 httpd nginx mysql mariadb
sudo systemctl disable apache2 httpd nginx mysql mariadb
1. Apache Web Server
Installation
1 | sudo apt update |
Start and enable
1 | sudo systemctl start apache2 |
Verify
Visit http://YOUR_PUBLIC_IP/. You should see the
Apache2 Ubuntu Default Page.
If you see "Unable to connect": 1. Check security
group (port 80 open?) 2. Check firewall: sudo ufw status 3.
Check Apache is running: sudo systemctl status apache2
Key directories
- Config:
/etc/apache2/apache2.conf - Virtual hosts:
/etc/apache2/sites-available/ - Document root:
/var/www/html/(default landing page) - Logs:
/var/log/apache2/access.log,/var/log/apache2/error.log
2. MySQL Database
Installation (Ubuntu uses MySQL, CentOS often uses MariaDB)
1 | sudo apt install -y mysql-server |
Run security wizard
1 | sudo mysql_secure_installation |
Follow the prompts:
- Set root password (strong, at least 12 chars)
- Remove anonymous users: Yes
- Disallow root login remotely: Yes (use SSH tunnel instead)
- Remove test database: Yes
Verify
1 | sudo systemctl status mysql |
Inside MySQL: 1
2
3SHOW DATABASES;
CREATE DATABASE test_lamp;
EXIT;
Common pitfall: Authentication plugin mismatch
MySQL 8.0+ uses caching_sha2_password by default, but
many PHP apps expect mysql_native_password. Fix:
1
2ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword';
FLUSH PRIVILEGES;
3. PHP and Extensions
Installation
1 | sudo apt install -y php libapache2-mod-php php-mysql |
Verify PHP integration with Apache
1 | echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php |
Visit http://YOUR_PUBLIC_IP/info.php. You should see a
PHP information page listing:
- PHP version (e.g., 7.4 or 8.1)
- Loaded extensions (check for
mysqli,pdo_mysql)
If you see the source code instead of the PHP info page:
- Apache is not processing
.phpfiles. Check:sudo a2enmod php7.4(replace with your version). - Restart Apache:
sudo systemctl restart apache2.
Install additional extensions (commonly needed)
1 | sudo apt install -y php-curl php-gd php-mbstring php-xml php-zip |
Part III: Deploying a Real Application (Discuz! Forum)
Discuz! is a popular PHP forum software. Deploying it reveals the most common LAMP pitfalls: file permissions, MySQL user creation, and PHP extension requirements.
1. Download and extract Discuz!
1 | cd /var/www/html |
2. Set directory permissions
Apache runs as user www-data (Ubuntu) or
apache (CentOS). It must be able to read/write certain
directories: 1
2sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html
For Discuz-specific directories (the installer
checks these): 1
2
3
4sudo chmod -R 777 /var/www/html/data
sudo chmod -R 777 /var/www/html/config
sudo chmod -R 777 /var/www/html/uc_server/data
sudo chmod -R 777 /var/www/html/uc_client/data
Security note: chmod 777 is convenient
but risky. After installation, tighten to 755 or
750.
3. Create MySQL database and user
1 | sudo mysql -u root -p |
Inside MySQL: 1
2
3
4
5CREATE DATABASE discuz CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'discuz_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON discuz.* TO 'discuz_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
4. Run the web installer
Visit http://YOUR_PUBLIC_IP/install/. The installer
will: 1. Check environment (PHP version, extensions) 2.
Check permissions (can it write to data/,
config/?) 3. Ask for database
credentials
Fill in:
- Database host:
localhost - Database name:
discuz - Database user:
discuz_user - Database password:
StrongPassword123!
If the installer complains about missing extensions, install them:
1
2sudo apt install -y php-mysqli php-gd
sudo systemctl restart apache2
5. Post-installation cleanup
After installation succeeds, delete the installer: 1
sudo rm -rf /var/www/html/install
Part IV: Troubleshooting Checklist
Problem 1: "Connection refused" when accessing site
Cause: Port blocked or service not running
Debug steps: 1. Check Apache is running:
sudo systemctl status apache2 2. Check listening ports:
sudo ss -tuln | grep 80 3. Check security group (port 80
open?) 4. Check OS firewall: sudo ufw status or
sudo firewall-cmd --list-all
Solution: 1
2sudo systemctl start apache2
sudo ufw allow 80/tcp
Problem 2: "403 Forbidden" when accessing a directory
Cause: Missing
index.php/index.html or directory
permissions
Debug steps: 1. Check if file exists:
ls -l /var/www/html/ 2. Check Apache can read it:
sudo -u www-data cat /var/www/html/index.php 3. Check
DirectoryIndex directive in Apache config
Solution: 1
2
3
4
5# Fix ownership
sudo chown -R www-data:www-data /var/www/html
# Or temporarily test with permissive permissions
sudo chmod -R 755 /var/www/html
Problem 3: PHP shows as plain text (source code visible)
Cause: Apache is not processing .php
files
Debug steps: 1. Check if PHP module is loaded:
apache2ctl -M | grep php 2. Check .htaccess or
virtual host config
Solution: 1
2
3
4
5# Enable PHP module (Ubuntu/Debian)
sudo a2enmod php7.4 # Replace with your PHP version
sudo systemctl restart apache2
# Verify: curl http://localhost/info.php (should see PHP output, not source)
Problem 4: "Can't connect to MySQL server on 'localhost'"
Cause: MySQL service not running or connection credentials wrong
Debug steps: 1. Check MySQL is running:
sudo systemctl status mysql 2. Test connection:
mysql -u discuz_user -p -h localhost 3. Check
bind-address in
/etc/mysql/mysql.conf.d/mysqld.cnf (should be
127.0.0.1 for localhost)
Solution: 1
2
3sudo systemctl start mysql
# If still failing, check MySQL error log:
sudo tail -f /var/log/mysql/error.log
Problem 5: Discuz installer says "Directory not writable"
Cause: Apache cannot write to required directories
Solution: 1
2sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 777 /var/www/html/data /var/www/html/config /var/www/html/uc_server/data /var/www/html/uc_client/data
After installation, tighten permissions: 1
sudo chmod -R 755 /var/www/html/data
Part V: Best Practices for Production LAMP
1. Never run as root
Always run services as dedicated users:
- Apache:
www-data(Ubuntu) orapache(CentOS) - MySQL:
mysql
2. Use virtual hosts for multiple sites
Instead of dumping everything in /var/www/html/, create
virtual hosts: 1
2
3
4
5
6
7
8<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example.com
<Directory /var/www/example.com>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Save to /etc/apache2/sites-available/example.com.conf,
then: 1
2sudo a2ensite example.com
sudo systemctl reload apache2
3. Enable HTTPS
Use Encrypt for free certificates: 1
2sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d example.com -d www.example.com
4. Harden MySQL
- Disable remote root login
- Use strong passwords (12+ chars, mixed case, symbols)
- Create per-app database users (never reuse
root)
5. Monitor logs
Set up log rotation and monitoring: 1
2
3
4
5
6# Apache logs
tail -f /var/log/apache2/access.log
tail -f /var/log/apache2/error.log
# MySQL logs
sudo tail -f /var/log/mysql/error.log
6. Automate backups
1 | # Database backup script |
Part VI: Source Compilation (Advanced)
If you need a specific version not available in repos, or want maximum optimization, compile from source.
Why compile from source?
Pros:
- Control over build flags (enable/disable features)
- Latest version (repos lag behind)
- Custom patches
Cons:
- Time-consuming (hours for MySQL)
- Manual dependency resolution
- No automatic security updates
Compiling MySQL 5.6 from source
Prerequisites
1 | sudo yum install -y gcc gcc-c++ cmake bison libaio-devel ncurses-devel zlib-devel openssl-devel |
Download and extract
1 | cd /usr/local |
Configure
1 | cmake . \ |
Compile (expect 1-3 hours)
1 | make -j$(nproc) |
Initialize
1 | sudo useradd -r -s /sbin/nologin mysql |
Create systemd service
1 | sudo cp support-files/mysql.server /etc/init.d/mysql |
Part VII: Real-World Case Studies
Case 1: Migrating from shared hosting
Scenario: Moving a WordPress site from GoDaddy to Alibaba Cloud ECS.
Steps: 1. Export database: mysqldump
from old host 2. Copy files via SFTP to /var/www/html 3.
Import database on new host 4. Update wp-config.php with
new DB credentials 5. Update DNS A record to new public IP
Pitfall: File permissions. On shared hosting,
everything is owned by your user. On ECS, Apache runs as
www-data. Fix:
sudo chown -R www-data:www-data /var/www/html.
Case 2: Running multiple sites (virtual hosts)
Scenario: Host blog.example.com and
forum.example.com on one instance.
Solution: Create two virtual hosts:
1
2
3
4
5
6
7
8
9
10
11# /etc/apache2/sites-available/blog.conf
<VirtualHost *:80>
ServerName blog.example.com
DocumentRoot /var/www/blog
</VirtualHost>
# /etc/apache2/sites-available/forum.conf
<VirtualHost *:80>
ServerName forum.example.com
DocumentRoot /var/www/forum
</VirtualHost>
Enable: 1
2sudo a2ensite blog forum
sudo systemctl reload apache2
Case 3: Handling PHP version conflicts
Scenario: Old app requires PHP 5.6, new app requires PHP 7.4.
Solution: Use php-fpm with different
versions: 1
2
3
4
5
6
7
8
9
10# Install both versions
sudo apt install -y php5.6-fpm php7.4-fpm
# Configure virtual host to use specific version
<VirtualHost *:80>
ServerName oldapp.example.com
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php5.6-fpm.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
Summary: LAMP in 5 Steps
- Open ports (security group + OS firewall)
- Install services (Apache, MySQL, PHP)
- Verify each layer (Apache serves HTML → PHP runs → MySQL connects)
- Set permissions (Apache user can read/write)
- Deploy app (Discuz, WordPress, etc.)
Next steps:
- Enable HTTPS with Encrypt
- Set up automated backups
- Monitor with Zabbix or Prometheus
- Explore Nginx as an Apache alternative
Further reading:
- Apache docs: https://httpd.apache.org/docs/
- MySQL reference: https://dev.mysql.com/doc/
- PHP manual: https://www.php.net/manual/en/
- Post title:LAMP Stack on Alibaba Cloud ECS: From Fresh Instance to Production-Ready Web Server
- Post author:Chen Kai
- Create time:2023-01-07 00:00:00
- Post link:https://www.chenk.top/en/lamp-on-ecs/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.