ACMAPI
Building the ACMAPI Relay
Background
The story began when I attended the ACM Honors Class midterm meeting at the end of April. At the meeting, senior wankupi said that no one in our class had volunteered to build an LLM API relay, so the sophomores collectively received yyu’s education once again. At that time, after being badly hit by Copilot Pro and Apple server bugs that prevented region changes, I was furious and started evaluating LLM relay services that could use the Opus series. I also became interested in building such a relay myself. Meanwhile, Parsifal told me that he wanted to earn money by building a relay. I was very tempted, because recently I had spent a large amount of money on tokens, servers, domains, IPs, and birthday gifts for many people. Even a young lady could not hold on forever, so I decided to earn some financial support myself. All these reasons led me to find senior kupi and take on the relay-building task. After nearly a full day of exploration on April 30, with P’s help, I had a fairly clear design and successfully ran it locally. So I decided to write a blog post recording the whole process of building an API relay from scratch.
Initial
At first, the idea was to deploy the relay on an overseas server and let that server forward requests to an overseas static residential IP, in order to avoid Anthropic’s almost terrifying risk controls. Later, after learning that we could obtain access to an ACM class server, we decided to deploy the relay on that server first, then forward subsequent requests to an overseas static residential IP.
A Small Episode
During the May Day holiday, I tried to work from home, but repeatedly failed to connect to the server. Later I learned that the IP under WSL was still my home IP, not the SJTU IP after connecting to the VPN, while the Windows IP was the SJTU IP. So I connected from Windows. Even after enabling Windows network mirroring for WSL, it still could not connect. This left another unresolved pitfall.
Relay Framework
Mainstream relay frameworks include oneAPI, newAPI, sub2API, and others. newAPI is the earliest and relatively most complete, but I had previously used an almost terrible site based on newAPI, so I did not have a good impression of it. In the end I chose sub2API, mainly because its code is relatively clean and its features are complete enough for our needs.
Frontend Polishing
I made some frontend beautification changes, turning sub2API into ACMAPI.
Domain and Intranet Tunneling
To let external users access the relay deployed on the server, we needed a domain and an intranet tunneling tool. We chose Cloudflare for tunneling because it is simple and provides free service. We registered a domain. A .top domain costs only 14 RMB, which made me wonder what my recently renewed 125 RMB .site domain even means. We pointed it to the address provided by Cloudflare, so external users could access our relay through the domain. It successfully ran locally.
At that moment, I did not know that the real challenges were still ahead.
Server Deployment
First, sub2API has a somewhat strange frontend/backend structure. The frontend is written in TypeScript and uses pnpm, while the backend is written in Go.
1 | cd frontend |
pnpm and go build were almost destructive for our ACM class server. The machine has very little memory and sits behind the SJTU firewall. pnpm build takes a lot of space, and the frontend exploded before compilation finished. The backend compilation was even worse. Go depends on many GitHub-hosted packages, and SJTU’s network environment is extremely unfriendly, causing dependency downloads to fail repeatedly and eventually breaking the build. After being stuck for a whole night, we changed strategy: compile everything locally and throw the results onto the server. Here we recommend rsync for data transfer. It is much, much more efficient than scp.
Next we installed the database and related services on the server, then did another round of tunneling. At that point, the relay deployed on the ACM class server could already be accessed normally.
Then we started considering IP proxy configuration. This was the biggest difficulty.
We found that a server deployed behind the SJTU firewall simply could not connect normally to a static residential IP. Overseas static residential IPs usually require an extra overseas datacenter IP proxy before sending requests. Naturally, the idea became: add a proxy layer on the ACM class server. But if the server could not even access GitHub, how could we install Clash? This became a dead loop. After another night of exploration, we finally installed Clash through a temporary proxy. Because of SJTU DNS restrictions, not every subscription worked with Clash. For this, I was forced to obtain several more proxies. Eventually I found a few that could subscribe successfully. Then, as expected, something unexpected happened. After two proxy layers, we could successfully connect to the overseas residential IP, but the double proxy caused a strange issue: we could not access Anthropic or OpenAI at all. It seemed like they detected the SJTU IP or datacenter IP somewhere in the path and blocked it directly.
So we concluded: it is not feasible to access Anthropic and OpenAI through a relay deployed on an on-campus server. Later, we tried the same setup on a Hong Kong server and succeeded. That became our current commercial relay, joypiggy. If you are interested, feel free to message me privately.
Just when I had run out of options, Boss Zheng told me that we only needed to connect to an upstream relay. Bruh. If it was that simple, I had already done it long ago. What even was that.
jAccount Authentication
This is the part I am proud of: from idea design to implementation and successful running, I completed it independently without outside intervention. jAccount authentication is an important feature of our relay. It ensures that only SJTU students can use it. The key is integrating with SJTU’s authentication system and verifying user identity information.
If you are interested, you can read this article. The final implementation added a jAccount login button on the frontend login page. After clicking it, users are redirected to SJTU’s authentication page, enter their jAccount username and password, and after successful authentication receive a token containing user information. Our relay verifies whether the token is valid, and if it is, allows the user to continue using the relay.
Regrets, or Maybe Future Work
Our original plan was to access it through acm.sjtu.edu.cn/llmapi, using an nginx reverse proxy configuration. Unfortunately, the backend base URL modification logic was too complex, and it seemed related to the jAccount authentication redirect URL. In the end, we could only use the domain I bought. Although that domain is cheap, I still want to solve this issue if there is a chance later.
Website Operations
Before this, I had no website operations experience at all. During the process, I encountered many problems: server environment configuration, database installation and configuration, domain DNS, intranet tunneling, and so on. Every problem gave me headaches. But through constant learning and trial, I eventually built the relay successfully. This is also the part that gave me the strongest sense of achievement.
Senior wankupi gave me many suggestions on website operations, including systemd service configuration and postgres database usage. Many thanks.
Conclusion
The reason we spent so much effort building this relay is, frankly, Anthropic and OpenAI’s various restrictions. It is quite emotional. Has study and research really become a war over tokens? I do not understand.
On April 30, 2026, I posted a topic on Shuiyuan: I want to know what fellow SJTU students think about API relays. https://shuiyuan.sjtu.edu.cn/t/topic/470419 SJTU students are welcome to vote.
And, to repeat once more, if anyone is interested in a cheap, full-power Codex relay without watered-down models, please contact me. Our current commercial relay joypiggy is already online. Welcome to use it.
Finally, thank you to all the seniors, classmates, and Shuiyuan friends who helped me. I am lucky to have you.





