<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 静亭雅苑</title>
    <description>The latest articles on DEV Community by 静亭雅苑 (@whjin).</description>
    <link>https://dev.to/whjin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4139420%2Ff1780af7-3bc7-41fd-8edc-51e55a796fde.png</url>
      <title>DEV Community: 静亭雅苑</title>
      <link>https://dev.to/whjin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whjin"/>
    <language>en</language>
    <item>
      <title>Can AI Write Verilog for FPGAs</title>
      <dc:creator>静亭雅苑</dc:creator>
      <pubDate>Wed, 14 Oct 2026 15:25:27 +0000</pubDate>
      <link>https://dev.to/whjin/can-ai-write-verilog-for-fpgas-2lam</link>
      <guid>https://dev.to/whjin/can-ai-write-verilog-for-fpgas-2lam</guid>
      <description>&lt;h1&gt;
  
  
  Can AI Actually Write Verilog for FPGAs? My Real-World Test
&lt;/h1&gt;

&lt;p&gt;As someone who does both full-stack web development and FPGA/Verilog programming, I was curious: can AI coding assistants handle hardware description languages?&lt;/p&gt;

&lt;p&gt;Everyone's talking about AI writing JavaScript, Python, and Rust. But what about Verilog? VHDL? Can an LLM actually understand hardware parallelism, timing constraints, and FPGA-specific quirks?&lt;/p&gt;

&lt;p&gt;I decided to put it to the test. Over the past month, I've been using AI tools (Claude, GPT-4, Cursor) on real FPGA projects. Here's what worked, what didn't, and whether AI is actually useful for hardware design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Was Skeptical
&lt;/h2&gt;

&lt;p&gt;I'm a self-taught FPGA developer. I know Verilog well enough to design working circuits, but I'm not a seasoned ASIC engineer. So I was hopeful that AI could help — but also skeptical.&lt;/p&gt;

&lt;p&gt;Hardware description languages are fundamentally different from software:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallel execution&lt;/strong&gt;: Everything happens at once, not step by step&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timing matters&lt;/strong&gt;: A bug that only shows up at 100MHz might be invisible in simulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource constraints&lt;/strong&gt;: FPGAs have fixed LUTs, flip-flops, and DSP blocks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Toolchain quirks&lt;/strong&gt;: Every FPGA vendor (Xilinx, Intel, Lattice) has its own weirdness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Could an LLM actually grok this?&lt;/p&gt;




&lt;h2&gt;
  
  
  Test 1: Basic Modules
&lt;/h2&gt;

&lt;p&gt;Let's start simple. I asked Claude to write a UART transmitter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "Write a Verilog module for a UART transmitter, 115200 baud, 8N1, 50MHz clock."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: It wrote a clean, well-structured UART transmitter. It had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A baud rate generator&lt;/li&gt;
&lt;li&gt;A shift register&lt;/li&gt;
&lt;li&gt;Start/stop bit logic&lt;/li&gt;
&lt;li&gt;Even added a parity bit option&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Was it correct? Mostly. I had to tweak the baud rate divisor calculation (it used 50MHz / 115200 ≈ 434, which is right), but the structure was solid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: ✅ Works well for standard building blocks. UART, SPI, I2C, PWM — all the common interfaces.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test 2: State Machines
&lt;/h2&gt;

&lt;p&gt;Next, I asked for a more complex design: a SPI master with a configurable register file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "Write a Verilog SPI master module that can read/write to internal registers, 4-wire SPI, mode 0."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: The output was good. It had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proper SPI mode 0 timing (CPOL=0, CPHA=0)&lt;/li&gt;
&lt;li&gt;A state machine for the SPI transaction&lt;/li&gt;
&lt;li&gt;An internal register bank&lt;/li&gt;
&lt;li&gt;Chip select handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing it got wrong: it used a blocking assignment (&lt;code&gt;=&lt;/code&gt;) in a sequential block where it should have used non-blocking (&lt;code&gt;&amp;lt;=&lt;/code&gt;). This is a classic Verilog gotcha — the kind of thing that simulation might not catch, but synthesis will hate.&lt;/p&gt;

&lt;p&gt;I caught it because I know what to look for. A beginner might not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: ⚠️ Good structure, but watch for subtle Verilog mistakes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test 3: Timing and Constraints
&lt;/h2&gt;

&lt;p&gt;Here's where things get interesting. Timing closure is one of the hardest parts of FPGA design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "My design has a 100MHz clock and I'm getting setup time violations. How do I fix this?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: It gave the standard advice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add pipeline registers&lt;/li&gt;
&lt;li&gt;Retime logic&lt;/li&gt;
&lt;li&gt;Use FPGA's built-in RAM blocks&lt;/li&gt;
&lt;li&gt;Check for combinational loops&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All good advice — but generic. It couldn't actually look at my specific timing report and tell me which path was the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: ⚠️ Good theoretical advice, but can't analyze your specific timing report.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test 4: Debugging Existing Code
&lt;/h2&gt;

&lt;p&gt;This is where I was most curious. Can AI help debug broken Verilog?&lt;/p&gt;

&lt;p&gt;I took a working SPI module and introduced a bug: I swapped the MOSI and MISO signals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "My SPI receiver isn't working. The data I'm getting is all zeros. Here's my code: [pasted Verilog]"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: It read through the code, spotted the MISO/MOSI mix-up within seconds. It explained why it was wrong and how to fix it.&lt;/p&gt;

&lt;p&gt;Impressive. But let's be honest — this was a simple bug. What about trickier ones?&lt;/p&gt;

&lt;p&gt;I tried a more subtle bug: a metastability issue where I forgot to double-synchronize an asynchronous input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "I'm getting random bit errors on my UART RX line. The design works in simulation but fails on hardware."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: It suggested checking for metastability issues. It mentioned that asynchronous inputs need proper synchronization. But it didn't pinpoint the exact issue because it couldn't see my full design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: ✅ Great for spotting obvious bugs. ⚠️ Harder for subtle timing/metastability issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test 5: FPGA-Specific Knowledge
&lt;/h2&gt;

&lt;p&gt;What about FPGA vendor-specific stuff? Like Xilinx UltraRAM, or Intel DSP blocks?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: "Write a Verilog design that uses a Xilinx DSP48E2 block to implement a FIR filter."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: It wrote the structure, but the DSP48E2 instantiation was wrong. It used generic names instead of the actual Xilinx primitive names.&lt;/p&gt;

&lt;p&gt;You'd need to know the exact primitive names, ports, and parameters — which AI doesn't always get right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verdict&lt;/strong&gt;: ⚠️ Good for generic logic, but vendor-specific primitives need manual correction.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Actually Saves Me Time
&lt;/h2&gt;

&lt;p&gt;After a month of using AI on FPGA projects, here's what actually saves time:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Boilerplate and Common Interfaces
&lt;/h3&gt;

&lt;p&gt;UART, SPI, I2C, PWM, I2S — all the standard building blocks. AI writes these correctly 90% of the time, saving me hours of looking up reference code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Testbenches
&lt;/h3&gt;

&lt;p&gt;Writing testbenches is tedious. AI is surprisingly good at them. Ask it to "write a testbench for this UART module that sends 0x55 and 0xAA and checks the output" — it does it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Explaining Existing Code
&lt;/h3&gt;

&lt;p&gt;Staring at someone else's Verilog for hours? Paste it into Claude and ask "what does this do?" It's surprisingly good at reverse-engineering.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Debugging Obvious Bugs
&lt;/h3&gt;

&lt;p&gt;Syntax errors, wrong port directions, missing &lt;code&gt;endmodule&lt;/code&gt; — AI catches these instantly.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AI Still Sucks At
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Timing Closure
&lt;/h3&gt;

&lt;p&gt;This is the hard part of FPGA design. AI can't read your timing report and tell you exactly which path to fix. You still need to understand setup/hold time, clock skew, and retiming yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Resource Optimization
&lt;/h3&gt;

&lt;p&gt;"Can I fit this design into a Lattice iCE40 with 1280 LUTs?" AI can estimate, but it can't actually run synthesis and see the real resource usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Vendor-Specific Tooling
&lt;/h3&gt;

&lt;p&gt;Xilinx Vivado, Intel Quartus, Lattice iCEcube2 — each has its own Tcl scripting, constraints format, and build flow. AI doesn't know the ins and outs of your specific toolchain.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Subtle Hardware Bugs
&lt;/h3&gt;

&lt;p&gt;Metastability, race conditions, glitches — these are the bugs that don't show up in simulation but eat you alive on real hardware. AI won't catch these unless you explicitly point them out.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Workflow Now
&lt;/h2&gt;

&lt;p&gt;Here's how I actually use AI for FPGA work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Design phase&lt;/strong&gt;: I sketch the block diagram myself. AI doesn't make architectural decisions for me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt;: I ask AI to write the boilerplate modules (UART, SPI, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt;: I wire everything together manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testbench&lt;/strong&gt;: AI writes the testbench.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging&lt;/strong&gt;: If simulation fails, I paste the code and ask AI for help.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthesis&lt;/strong&gt;: I run the tools myself. AI doesn't touch the timing constraints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AI is a copilot, not the pilot. It handles the tedious parts, I handle the architecture and the tricky bits.&lt;/p&gt;




&lt;h2&gt;
  
  
  Should FPGA Developers Use AI?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes, with caveations.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI is great for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing standard building blocks&lt;/li&gt;
&lt;li&gt;Generating testbenches&lt;/li&gt;
&lt;li&gt;Debugging obvious bugs&lt;/li&gt;
&lt;li&gt;Explaining unfamiliar code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI is NOT good for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architectural decisions&lt;/li&gt;
&lt;li&gt;Timing closure&lt;/li&gt;
&lt;li&gt;Vendor-specific optimization&lt;/li&gt;
&lt;li&gt;Subtle hardware bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of AI as a junior engineer. It can crank out working code for well-defined tasks, but you still need to review it carefully. And for the hard problems — timing, resources, architecture — you're still the one in charge.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;AI won't replace FPGA engineers anytime soon. Hardware design is too nuanced, too tied to specific hardware, too dependent on real-world measurement.&lt;/p&gt;

&lt;p&gt;But AI will make FPGA developers more productive. The tedious boilerplate that used to take hours? Now it takes minutes. The time saved can go into the hard parts — architecture, optimization, testing — where it actually matters.&lt;/p&gt;

&lt;p&gt;If you're an FPGA developer and you're not using AI yet, you're spending too much time writing UART and SPI modules from scratch.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This was based on real FPGA development work on &lt;a href="https://wuhuajin.com" rel="noopener noreferrer"&gt;wuhuajin.com&lt;/a&gt;. If you're also doing FPGA + software development, I'd love to hear how you're using AI tools.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I Deployed a Music API with Docker on Alibaba Cloud in 30 Minutes</title>
      <dc:creator>静亭雅苑</dc:creator>
      <pubDate>Fri, 09 Oct 2026 14:31:00 +0000</pubDate>
      <link>https://dev.to/whjin/how-i-deployed-a-music-api-with-docker-on-alibaba-cloud-in-30-minutes-2mkj</link>
      <guid>https://dev.to/whjin/how-i-deployed-a-music-api-with-docker-on-alibaba-cloud-in-30-minutes-2mkj</guid>
      <description>&lt;h1&gt;
  
  
  用 Docker 部署 Meting API：从阿里云到 HTTPS 域名的完整实操
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;部署一套自己的音乐接口服务，最省心、可复现的方式就是用 Docker 跑 &lt;code&gt;Meting API&lt;/code&gt;。本文基于我在阿里云 ECS 上的真实踩坑经验，把从安装 Docker、拉取镜像、运行容器，到最后用 Nginx + 证书把 IP 升级成 HTTPS 域名的&lt;strong&gt;完整命令&lt;/strong&gt;一次性给你，照着复制即可。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;你将得到：&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;阿里云 &lt;code&gt;Alibaba Cloud Linux 3&lt;/code&gt; 下安装 &lt;code&gt;docker-ce&lt;/code&gt; 的正确姿势（含 &lt;code&gt;$releasever&lt;/code&gt; 的坑）&lt;/li&gt;
&lt;li&gt;拉不动 &lt;code&gt;ghcr.io&lt;/code&gt; 官方镜像时，&lt;code&gt;git clone&lt;/code&gt; + 本地 &lt;code&gt;docker build&lt;/code&gt; 的备用方案&lt;/li&gt;
&lt;li&gt;镜像加速器配置 + 运行容器 + 端口放行&lt;/li&gt;
&lt;li&gt;IP 地址 → 域名 → HTTPS 的完整升级路径&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  先讲清楚：为什么要用 Docker
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Meting API&lt;/code&gt; 本身是一个轻量的音乐接口服务（配合 APlayer 播放器使用）。用 Docker 部署的好处是&lt;strong&gt;环境隔离、一键起停、换服务器无缝迁移&lt;/strong&gt;——不用在系统里装一堆依赖，也方便后续用 &lt;code&gt;docker-compose&lt;/code&gt; 编排。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;想了解更完整的部署思路和细节，可参考我维护的完整教程：&lt;a href="https://wuhuajin.com/src/template/posts/%E5%B7%A5%E7%A8%8B%E5%8C%96/html/Docker%E9%83%A8%E7%BD%B2Meting%20API%E6%9C%8D%E5%8A%A1.html" rel="noopener noreferrer"&gt;Docker部署Meting API服务（完整版）&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  前置条件
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;一台&lt;strong&gt;阿里云 ECS&lt;/strong&gt;（本文以 &lt;code&gt;Alibaba Cloud Linux 3&lt;/code&gt; 为例，CentOS/其他发行版原理相同）&lt;/li&gt;
&lt;li&gt;一个域名（用于最后的 HTTPS 升级；只想要 IP 访问可以跳过）&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sudo&lt;/code&gt; 权限&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  第 1 步：安装 Docker（阿里云官方源）
&lt;/h2&gt;

&lt;p&gt;在阿里云机器上，最稳的方式是用&lt;strong&gt;阿里云内网镜像源&lt;/strong&gt;。有两个容易踩的坑：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;mirrors.cloud.aliyuncs.com&lt;/code&gt; 是内网地址，ECS 上用速度最快；&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Alibaba Cloud Linux 3&lt;/code&gt; 的 &lt;code&gt;$releasever=3&lt;/code&gt;，但 &lt;code&gt;docker-ce&lt;/code&gt; 源是按 &lt;strong&gt;CentOS 8&lt;/strong&gt; 组织的，所以要手动把变量替换成 &lt;code&gt;8&lt;/code&gt;。
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1) 添加 docker-ce 源（用 curl，阿里云内网镜像）&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/yum.repos.d/docker-ce.repo http://mirrors.cloud.aliyuncs.com/docker-ce/linux/centos/docker-ce.repo
&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s|https://mirrors.aliyun.com|http://mirrors.cloud.aliyuncs.com|g'&lt;/span&gt; /etc/yum.repos.d/docker-ce.repo

&lt;span class="c"&gt;# 2) 关键：把 $releasever 替换成 8（等价于 releasever-adapter 插件的作用）&lt;/span&gt;
&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s|\$releasever|8|g'&lt;/span&gt; /etc/yum.repos.d/docker-ce.repo

&lt;span class="c"&gt;# 3) 刷新缓存并安装&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf clean all
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io docker-compose-plugin

&lt;span class="c"&gt;# 4) 启动并验证&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; docker
docker &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  第 2 步：获取镜像
&lt;/h2&gt;

&lt;p&gt;优先直接拉官方镜像；如果 &lt;code&gt;ghcr.io&lt;/code&gt; 拉不动（国内常见），就用&lt;strong&gt;代码本地构建&lt;/strong&gt;兜底。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;方式 A：直接拉官方镜像&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull ghcr.io/metowolf/meting-api:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;方式 B：git clone 后本地构建&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;git
git clone https://github.com/whjin/Meting-API.git /opt/meting-api   &lt;span class="c"&gt;# 慢可换 https://ghfast.top/https://github.com/...&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/meting-api
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; meting-api &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;配置 Docker 镜像加速器&lt;/strong&gt;（拉镜像慢时很有用）：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1) 创建配置&lt;/span&gt;
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/docker
&lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/docker/daemon.json &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
{
  "registry-mirrors": ["https://docker.m.daocloud.io"]
}
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="c"&gt;# 2) 重启 Docker 生效&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart docker

&lt;span class="c"&gt;# 3) 重新构建&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /opt/meting-api
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; meting-api &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;想拿阿里云专属加速器地址（ECS 用户最稳）：阿里云控制台 → 搜索"容器镜像服务 ACR" → 左侧"镜像工具 → 镜像加速器"，页面会显示形如 &lt;code&gt;https://xxxx.mirror.aliyuncs.com&lt;/code&gt; 的专属地址，替换 &lt;code&gt;registry-mirrors&lt;/code&gt; 即可。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  第 3 步：运行容器
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;METING_URL&lt;/code&gt; 记得带上 &lt;code&gt;:8000&lt;/code&gt;，&lt;code&gt;METING_TOKEN&lt;/code&gt; 用随机密钥：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1) 删掉旧容器（-f 强制，保险）&lt;/span&gt;
docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; meting-api

&lt;span class="c"&gt;# 2) 重新运行&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; meting-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 80:80 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;METING_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://你的服务器公网IP:8000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;METING_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;换成你自己的随机密钥 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt; unless-stopped &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/metowolf/meting-api:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;生成随机密钥：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  第 4 步：放行端口
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;阿里云安全组&lt;/strong&gt;：ECS 控制台 → 实例 → 安全组 → 入方向规则 → 添加 80 端口（或自定义端口，如 8000），授权对象 &lt;code&gt;0.0.0.0/0&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;系统防火墙&lt;/strong&gt;：
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--add-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8000/tcp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;span class="c"&gt;# 如果没开 firewalld 可忽略&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;80 端口被占用时，可改用 8000 端口。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  第 5 步：验证
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 本机验证（用 localhost，不要 curl 自己的公网 IP）&lt;/span&gt;
curl &lt;span class="s2"&gt;"http://localhost:8000/api?server=netease&amp;amp;type=search&amp;amp;id=周杰伦"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;浏览器打开 &lt;code&gt;http://你的公网IP:8000/api?server=netease&amp;amp;type=search&amp;amp;id=周杰伦&lt;/code&gt; 能返回 JSON，说明服务已经通了。&lt;/p&gt;




&lt;h2&gt;
  
  
  进阶：把 IP 升级为 HTTPS 域名
&lt;/h2&gt;

&lt;p&gt;IP 直接访问不安全也不好记，升级到域名 + HTTPS 只需 4 步：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;域名解析&lt;/strong&gt;：在域名控制台添加一条 A 记录，指向服务器公网 IP；&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx 反向代理&lt;/strong&gt;：在 &lt;code&gt;/etc/nginx/conf.d/meting.conf&lt;/code&gt; 配置，同时包含 HTTP 和 HTTPS；&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;签发证书&lt;/strong&gt;：用 &lt;code&gt;certbot&lt;/code&gt; 自动申请并安装证书；&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;更新容器&lt;/strong&gt;：把 &lt;code&gt;METING_URL&lt;/code&gt; 改为域名地址并重启容器。
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 重载 Nginx 配置&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nt"&gt;-s&lt;/span&gt; reload nginx

&lt;span class="c"&gt;# 重新安装证书&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cert-name&lt;/span&gt; meting.wuhuajin.com

&lt;span class="c"&gt;# 验证 HTTPS 是否通&lt;/span&gt;
curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://meting.wuhuajin.com/api?server&lt;span class="o"&gt;=&lt;/span&gt;netease&amp;amp;type&lt;span class="o"&gt;=&lt;/span&gt;search&amp;amp;id&lt;span class="o"&gt;=&lt;/span&gt;周杰伦

&lt;span class="c"&gt;# 更新容器 METING_URL 为域名&lt;/span&gt;
docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; meting-api
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; meting-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:80 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;METING_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://meting.wuhuajin.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;METING_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;你的密钥 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt; unless-stopped &lt;span class="se"&gt;\&lt;/span&gt;
  meting-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;完整命令与更多细节（含 Nginx 配置写法），见 &lt;a href="https://wuhuajin.com/src/template/posts/%E5%B7%A5%E7%A8%8B%E5%8C%96/html/Docker%E9%83%A8%E7%BD%B2Meting%20API%E6%9C%8D%E5%8A%A1.html" rel="noopener noreferrer"&gt;完整版教程&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  小结
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;用 &lt;strong&gt;阿里云内网源&lt;/strong&gt; 装 &lt;code&gt;docker-ce&lt;/code&gt;，记得把 &lt;code&gt;$releasever&lt;/code&gt; 替换成 &lt;code&gt;8&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;拉不动镜像就 &lt;strong&gt;git clone + 本地 build&lt;/strong&gt;，再配 &lt;strong&gt;镜像加速器&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;容器端口映射、安全组 + &lt;code&gt;firewalld&lt;/code&gt; 放行缺一不可；&lt;/li&gt;
&lt;li&gt;要上 HTTPS，走 &lt;strong&gt;A 记录 + Nginx 反代 + certbot&lt;/strong&gt; 三步。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;部署完成后，配合 APlayer 前端组件即可在前端页面播放音乐。如果你也在自建音乐 API 服务，欢迎收藏、转发这篇文章，也欢迎到原文评论区交流踩坑经验。&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>devops</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
