Preface
As the title suggests, I recently spent a few days building a company official website, and on top of that, I’ve developed several sub‑sites for the company over the past few months. During the actual deployment, I ran into a few pitfalls—especially regarding domain‑to‑IP mapping—so I’d like to summarise and document them here.
To make the overall narrative more coherent, I’ll also briefly cover the basic process of developing a web site in the early stages.
Web Site Development Process
In a nutshell, developing a web site can be broken down into several phases: feasibility study, requirements analysis, prototyping, UI design, coding, testing, and deployment. Take the simplest example: one day the company leadership asks us to build an official website. We might have a quick chat about the rough requirements, then start writing a requirements document—or sometimes, to save time, we jump straight into building a prototype page using AI tools. In today’s AI era, we can use AI assistance in most software development and design scenarios. Common tools include Codex, Claude, Workbuddy, Traebuddy, Codebuddy, Trae, Cursor (and even VS Code with relevant AI plugins), etc. Some of these are better suited for writing documentation and requirements, while others excel at code generation—I won’t draw a strict distinction here.
So we might design the prototype directly according to the leadership’s requirements. After a prototype review, we send the revised prototype to the UI designers, who then produce the corresponding UI designs. Here too, the workflow differs from the past. For example, we used to use tools like Axure for prototyping—that’s certainly not wrong, but dragging and dropping components is relatively inefficient. Now we can organise the requirements into a document, feed it to an AI tool, and let the AI generate the corresponding web site directly—with mock data for any data‑interaction parts. Then we deploy the prototype web site (or simply make it accessible internally, e.g., via internal IP + port, which most front‑end frameworks support) and share the address with the UI designers so they can base their designs on the prototype. Ideally, after the UI designers finish the design drafts, they no longer need to hand over a bunch of static image files to the developers; instead, they can provide HTML/Vue/TSX files directly from the UI design platform—many platforms now support that. This greatly improves efficiency compared to the old way. In the past, front‑end engineers had to manually reconstruct the UI from the design drafts—downloading image assets, picking colours, extracting styles, adjusting layouts, tweaking margins and paddings, etc. This approach seems rather inefficient in the AI era. For instance, if the company uses a React‑based tech stack, the UI designers can directly provide TSX files for each page. The developers then build on top of those engineering files—setting up databases, developing APIs, binding interfaces, implementing interactions, and so on. This means the era of splitting development into two separate groups—front‑end and back‑end—is gradually fading. Of course, separation of front‑end and back‑end during development is still necessary—it’s an architectural improvement—but it doesn’t require two distinct teams.
The Gradual Disappearance of Front‑end / Back‑end Engineer Titles
What I mean is that the titles “front‑end engineer” and “back‑end engineer” are slowly becoming unnecessary (of course, this applies to projects of moderate scale; for large or specialised projects, these two groups may still exist). In practice, the work will be taken over by a single group of people (who were previously front‑end, back‑end, or full‑stack engineers). The reason is that while the separation of front‑end and back‑end has improved overall web development efficiency, it has also introduced a new pain point: front‑end/back‑end integration. Integration is the process where, after the front‑end has built the pages and the back‑end has developed the APIs, the front‑end begins to gradually consume those APIs. In the past, we often saw scenarios like: front‑end developers saying the pages are done, but many buttons and pages are non‑clickable; back‑end developers saying the APIs are ready, but many endpoints return 500 or 404; the front‑end complaining that a certain field is missing from the response, and the back‑end saying “it’s by design” – these issues are all real. If the estimated coding effort was, say, 50 person‑days, the time spent on integration might exceed 25 person‑days, of which only about 10 person‑days were actually productive. Now, with the rise of AI, both front‑end and back‑end engineers can transition into general‑purpose engineers. When developing larger projects, instead of dividing responsibilities by front‑end/back‑end, we can assign tasks by functional modules. The key point is that everyone involved should be familiar with the logic of both front‑end and back‑end development. That is, even if I don’t know the exact code details, I should understand the overall flow, how the database should be designed, which features belong on the back‑end, which on the front‑end, and what I expect the outcome to look like. Then we feed this information—in text, images, etc.—to AI tools, and let the AI carry out the actual implementation.
After the general‑purpose engineers have restored the UI designs and developed the corresponding functionality, they need to perform self‑testing. Once the basic features pass, they can submit the functional modules to testers for formal testing. Testers still follow traditional black‑box testing processes—e.g., looking at the system from a user’s perspective and raising various issues. Of course, in the AI era, testers can also use AI tools to assist with other types of testing, such as back‑end API testing, stress testing, performance testing, security testing, etc. In the past, these would have required a lot of coding; now that coding effort is much reduced.
Web Site Deployment
After testing is completed, the site is deployed. Large companies have dedicated operations personnel; smaller companies leave this task to regular developers. I missed a small point here: typically, web site runtime environments are divided into development, testing, and production environments; sometimes there’s also a pre‑release environment. Testing is usually carried out in the testing environment. After final testing passes, the project is released to the production environment. Production environments are usually accessed via a domain name. This brings up a classic interview question: what happens when we type a URL into a browser and see the corresponding web content? Typically, a company purchases one or more domain names—e.g., google.com, jd.com, etc. There are many domain suffixes, such as .cn, .com, .org, .net, .top, .cc, etc. Different suffixes have different meanings and different prices (also affected by the length of the domain name itself). You can refer to other resources for more details—I won’t cover them here. After purchasing a domain (usually from domain registrars like Alibaba Cloud, Tencent Cloud, etc.), you also need to configure DNS resolution services—i.e., mapping the domain to a public IP address. For example, when we type google.com into the browser, the browser first looks up the DNS record for that domain from local or various DNS servers, then accesses the corresponding public IP. The default port for HTTP is 80, and for HTTPS it’s 443. Of course, some domains or IPs may use other ports, like 8080, 9090, etc. One thing to note: in China, if you want to operate a website properly, you also need to apply for ICP filing and public security filing (and some other services may require additional licences). The relevant filing information must be placed prominently at the bottom of the site. If not, and the regulatory authorities find out, they may call you or force the site offline for rectification. Also, if you need to enable HTTPS, you usually have to purchase an SSL/TLS certificate. There are indeed free ones available, but they typically expire in 1‑3 months, so you have to re‑apply. Paid certificates have longer validity—usually 1‑2 years, sometimes shorter, like half a year. They also come in wildcard and specific‑domain variants, with different prices. For example, *.google.com is a wildcard certificate and costs more; a specific one like example.google.com is cheaper.
Back to the main topic: after we configure the DNS resolution to point to the company’s public IP (which could be a self‑hosted server or a cloud server like Alibaba Cloud mentioned earlier), the simplest approach is to deploy our developed project directly onto that public IP’s server. For instance, deploy it on port 443, so users can access the web site via the domain name, e.g., example.com. However, this approach has a problem: if we develop several new web sites that also need to be exposed externally (or even if the deployment server doesn’t have a public IP, only an internal one), we could open new public IPs or deploy on other ports of the same IP. But this has several drawbacks: first, we have to constantly update DNS resolution records—each new site requires a new DNS record; second, if we deploy on non‑80/443 ports, users have to access it as domain:port, e.g., example:8080—which looks ugly and adds to the user’s memory burden. So how do we usually handle this? The answer is Nginx reverse proxy.
Nginx Reverse Proxy
First, we need to deploy an Nginx service on the public IP that corresponds to the DNS resolution (can be done with Docker or a direct installation). Depending on the business scale, this server can be dedicated to Nginx (though you can also run other services on it). Below is a sample Nginx configuration file:
# Extract SSL settings for reuse across multiple server blocks
# /etc/nginx/conf.d/ssl_common.conf
# ssl_certificate and ssl_certificate_key are NOT included here – each server defines its own certificate paths.
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
client_max_body_size 1024M;
# --------------------------
# Port 80: Redirect all HTTP requests to HTTPS (301)
# --------------------------
server {
listen 80;
listen [::]:80;
# Key: match both the naked domain and all subdomains
server_name example.com *.example.com;
# Permanent redirect, preserving original request URI
return 301 https://$host$request_uri;
}
# --------------------------
# 1. Naked domain example.com – official website entry
# Proxy to internal business service at 192.168.xx.xx:3000
# --------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
# HTTPS certificate paths
ssl_certificate /etc/nginx/conf.d/v2x.example.com_nginx/example.com_ca.crt;
ssl_certificate_key /etc/nginx/conf.d/v2x.example.com_nginx/example.com.key;
# Include common SSL settings
include /etc/nginx/conf.d/ssl_common.conf;
location / {
proxy_pass http://192.168.xx.xx:3000;
# Essential proxy headers to pass client real info to backend
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
tcp_nodelay on;
}
# Error pages for backend 5xx errors
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# --------------------------
# 2. www.example.com – permanent redirect to naked domain
# --------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /etc/nginx/conf.d/v2x.example.com_nginx/example.com_ca.crt;
ssl_certificate_key /etc/nginx/conf.d/v2x.example.com_nginx/example.com.key;
include /etc/nginx/conf.d/ssl_common.conf;
# 301 permanent redirect, preserving request path and parameters
return 301 https://example.com$request_uri;
}
# --------------------------
# 3. v2x.example.com – mini‑program API backend
# Proxy to internal 192.168.xx.yy:8080
# --------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name v2x.example.com;
ssl_certificate /etc/nginx/conf.d/v2x.example.com_nginx/example.com_ca.crt;
ssl_certificate_key /etc/nginx/conf.d/v2x.example.com_nginx/example.com.key;
include /etc/nginx/conf.d/ssl_common.conf;
location / {
proxy_pass http://192.168.xx.yy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
tcp_nodelay on;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
# --------------------------
# 4. avo.example.com – web admin backend
# Proxy to internal 192.168.xx.yy:9090
# --------------------------
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name avo.example.com;
ssl_certificate /etc/nginx/conf.d/v2x.example.com_nginx/example.com_ca.crt;
ssl_certificate_key /etc/nginx/conf.d/v2x.example.com_nginx/example.com.key;
include /etc/nginx/conf.d/ssl_common.conf;
location / {
proxy_pass http://192.168.xx.yy:9090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
tcp_nodelay on;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
In this example, I’ve separated the SSL (HTTPS) certificate configuration per server block to handle cases where different sites (including sub‑domains) use different certificates. If all sites share the same certificate, you can consolidate them. This is a shared Nginx configuration file – a single Nginx instance serves as the unified HTTPS entry point, using one wildcard certificate, exposing only port 443 externally, and reverse‑proxying to multiple internal/backend services based on the requested domain. I’ve hidden specific domain and IP details for privacy. This Nginx setup primarily does the following:
-
example.com→ internal 192.168.xx.xx:3000 (official website service) -
www.example.com→ 301 redirect toexample.com -
v2x.example.com→ internal 192.168.xx.yy:8080 (API interface service) -
avo.example.com→ internal 192.168.xx.yy:9090 (web admin backend) - All HTTP (80) requests are forced to 301 redirect to HTTPS (443)
The benefits are numerous: first, we only need to configure DNS once (DNS changes take time to propagate, and we might not always have permission to access the company’s DNS management system); second, any internal/public IP + any port can be accessed via https://subdomain format – both aesthetically pleasing and secure; third, all business sites are centralised under one Nginx service, making management and understanding easier, and avoiding the hassle of mapping internal IPs to public IPs. Additionally, we can leverage Nginx for load balancing, traffic control, and static/dynamic separation – so this approach is all gain and no pain.
Summary
In the AI era, change is rapid – we see both the reuse of old technologies and the adoption of new ones, along with significant productivity improvements. However, I’ve always believed that the programmer profession and these job roles will not be replaced. What will change is the nature of our work – much like the Industrial Revolution, where trains replaced horse‑drawn carriages, but the carriage drivers could still find work at railway stations – the demand for human mobility never disappeared. What we should do, instead, is embrace lifelong learning.
Top comments (0)