Open-source project
lhccong/fish-island-backend avatar
lhccong/fish-island-backend

fish-island-backend: a Spring Boot backend that aggregates Chinese hot lists and proxies the awkward parts

摸鱼岛🎣后端 基于爬虫 ➕ Netty ➕ SpringBoot ➕Redis➕ MySQL 开源🌟一站式摸鱼网

712 stars103 forksJavaLicense varies

At a glance

What is it?
fish-island-backend is the Java server behind the Moyu Island site, combining crawlers, Netty, Spring Boot, Redis and MySQL to pull trending lists from a dozen Chinese platforms and to serve a chat room, a reader, small games and a toolbox. It suits someone who wants to self-host that kind of aggregator, and it does nothing for a project that just needs a JSON API over one upstream.
Who is it for?
fish-island-backend is worth running if you want the aggregator itself rather than the hosted site, because the crawler aggregation, the Redis caching layer and the MySQL schema are all in the repository, and because the nginx configuration in the project documentation shows exactly which traffic goes to the HTTP service on port 8123 and which goes to the WebSocket service on port 8090.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 33 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A backend for a site, not a general purpose hot list API

The repository is the server side of Moyu Island, and the project description puts it in one line as built on crawlers, Netty, Spring Boot, Redis and MySQL, as a one-stop slacking site. The primary language is Java, the homepage is yucoder.cn, and the front end lives in a separate repository, fish-island-frontend.

That separation matters for what this project is. The feature list in the project documentation is organised by the site's sections rather than by API resources. There is data aggregation across many sources, a daily to-do feature, the chat room, the reading section, small games, a toolbox, avatar frame exchange, and a set of odds and ends like a music player, a salary calculator that counts down to the next holiday, a favicon changer and a blinking title notification.

The aggregation list names the sources individually: Zhihu, Weibo, Hupu, Coder Navigation, CSDN, Juejin, Bilibili, Douyin, NetEase Cloud Music, and Smzdm, with the last entry marked as to be filled in. NetEase Cloud Music is called out as supporting playback on the site itself, which is a hint that this list is scraped rather than proxied through a documented API.

The rest of the feature list is a set of small applications. The chat room supports emoji stickers, Sogou online stickers, link parsing, markdown rendering, an AI assistant backed by the SiliconFlow model, avatar frames, geolocation display, user titles, invitations to play gomoku or Chinese chess, red packet sending, and CV image sending. The reader has online book search, a small window viewing mode, and custom book sources. The games are gomoku and Chinese chess, both against a machine or another player, plus 2048. The toolbox holds JSON formatting, text diffing, aggregated translation, Git commit message generation, an AI agent and an AI weekly report assistant.

The homepage of the project at yucoder.cn is the hosted stable version, and an online demo is linked from the project documentation.

The deployment path is SQL, configuration, Maven, Docker

The deployment section is a five step list, and the order is the point.

First, run the initialisation SQL, which is the create_table.sql file in the sql/ directory. Second, change the MySQL address, the Redis address, the Minio address and the email sending configuration. Third, package with Maven. Fourth, deploy with Docker, and the Dockerfile is given in the project documentation. Fifth, configure nginx.

The Dockerfile in the project documentation is a Java 8 image:

dockerfile
FROM openjdk:8
ENV workdir=/cong/fish
COPY . ${workdir}
WORKDIR ${workdir}
EXPOSE 8123
CMD ["java","-jar","-Duser.timezone=GMT+08","fish-island-backend-0.0.1-SNAPSHOT.jar"]

The repository at the top level has a different and newer Dockerfile, based on eclipse-temurin:17, which copies the packaged jar rather than the whole source tree, creates the work directory at /home/cong/fish, makes the jar executable, and exposes the same port 8123 with the same command line and the same user.timezone setting. Two Dockerfiles that disagree about the base image and the copy strategy is a small sign of a project that has moved forward while its readme lags.

The build and run commands are given as a shell block, and the run line is notable for publishing two ports, 8123 and 8090:

shell
  docker build -f ./dockerfile -t fish .

The two ports are the key architectural fact, and the nginx configuration in the project documentation confirms it. The location block for /fish/ proxies to the backend on port 8123, and a separate location block for /ws/ proxies to port 8090 with proxy_http_version 1.1, the Upgrade and Connection headers set, and a Chinese comment explaining that HTTP/1.1 is required for the WebSocket upgrade. So the HTTP API and the WebSocket service are separate listeners in the same process, and the reverse proxy is what joins them into one origin.

The nginx configuration shows the third-party services it depends on

The nginx configuration in the project documentation is the most revealing document in the repository, because it shows the full set of external services the site leans on.

Besides the two backend routes, there is a location for /sogou-api/ that proxies to pic.sogou.com, sets the Host header to pic.sogou.com, forwards the real IP and the forwarded-for header, enables proxy_ssl_server_name, and adds permissive CORS headers with an OPTIONS preflight branch returning 204. That block exists because the chat room fetches Sogou stickers, and the sticker service does not send CORS headers itself, so the server proxies it and adds them.

There is a location for /holiday/ that proxies to date.appworlds.cn. It sets the Host header to date.appworlds.cn, spoofs a desktop browser User-Agent so the server does not return HTML, and forces an Accept of application/json. The comments explain both workarounds in Chinese: keeping the target host avoids a default page, and pretending to be a browser prevents the server from deciding to serve HTML. The same permissive CORS block and preflight branch is repeated here.

The main location serves the static front end from /usr/share/nginx/fish with a try_files fallback to index.html, which is the standard single page application rewrite, and the first server block redirects plain HTTP permanently to HTTPS.

So the site makes at least two outbound calls to third-party Chinese services on behalf of the browser, proxied through the same nginx. A self-hosted deployment therefore inherits a dependency on those upstreams being reachable and being shaped the way the configuration expects, and it also means the server is making requests that look like they come from it, not from the user's browser.

The crawler layer is where the fragility lives

The description says the stack is built on crawlers, and that is the part of the system with no interface, no contract and no version. A hot list from Zhihu, Weibo or Douyin is a web page that gets restructured whenever the platform decides to, and a crawler that reads it has to be updated when it does.

The presence of Netty in the stack is consistent with that. Netty is a network framework, and using it for a service that both talks to many upstream HTTP endpoints and holds long-lived WebSocket connections for the chat room and the games is a reasonable choice. The MySQL layer then stores the historical data, and the Redis layer sits in front of it, which is what makes the trending lists cheap to serve and lets the chat and the games run on the same box as the aggregation.

The two games with online matches, the chat room with user locations and red packets, and the AI assistant all run on top of the same Spring Boot service, which means one process carries both the polling of third-party sites and the low latency traffic of people typing at each other. That is a coherent choice for a small site, and it is also a coupling: a slow upstream scrape and a busy chat room share the same container.

The project documentation also points at a related file in the repository root, a document titled in Chinese about adding the LinuxDo data source, which shows that new sources are added by writing a new crawler and registering it, and that the list of sources is actively extended.

The open source terms require attribution, which is unusual and worth reading

The repository's licence is not classified, and the project documentation carries a note that is more specific than a licence file. It says the project is open source, that users must show the author's name on the site along with a link to the project, that if they do not want to keep the attribution they must first obtain authorisation, and that it must not be used for illegal purposes.

That is an attribution requirement attached to an open source project, and it sits oddly next to the MIT licence that the family of similar projects usually use. There is a LICENSE file in the repository tree, but the metadata records the licence as unknown, so what the file actually grants is not something this description can answer. Anyone deploying this for a commercial site, or anyone who wants to rebrand it, needs to read the licence file and, if it does not cover the attribution requirement, contact the author.

The project documentation also carries a warning specific to self-hosting: when you deploy privately, remember to change the back end interface address path to point at your own instance. The front end is a separate repository, so a self-hosted deployment means two repositories to configure, and the address in the front end has to match your domain.

The project's own state description gives a sense of scale, and it is the kind of claim the documentation makes about itself rather than a technical fact: various public accounts have shared it, the personal site has passed a thousand users, and the peak real-time online count reached 80 or more. The last push to the repository was on 2026-09-20, the repository is not archived, and it has no GitHub releases, so the versioning is whatever the Maven artifact version happens to be.

Where fish-island-backend is the wrong tool

The first limit is that it is a site, not a library. There is no published API client, no versioning policy for the HTTP surface, and no changelog of breaking changes. If what you want is trending data for your own application, pulling this service means depending on an undocumented API of an application server that also serves a chat room and two chess games.

The second is the scraping. Every source in the aggregation list is a web page that the upstream platform can change at any time, and there is no upstream contract. Your deployment inherits the maintenance burden of the crawlers, and the project documentation inclusion of a document about adding a new data source is a reminder that this is ongoing work rather than a solved problem.

The third is the operational surface. The service needs MySQL, Redis, Minio for object storage, an email configuration for sending, and a reverse proxy configured in three places for HTTP, WebSocket and the proxied third-party routes. The project documentation gives you the nginx configuration as a starting point rather than a managed setup, and the two Dockerfiles disagree about base image and build strategy, so the deployment instructions need reading twice.

The fourth is the hardcoded JVM and stack choices. The Dockerfile in the project documentation is on openjdk 8 while the repository one is on eclipse-temurin 17, and the jar is built with -Duser.timezone=GMT+08 baked into the command, which means timezone-sensitive behaviour is fixed at the container level rather than configurable. A project with different regional or timezone expectations cannot change that without editing the image.

The fifth is the licence question, which for an organisation is the one to resolve first. The metadata does not classify the licence, and the project documentation imposes an attribution obligation that is stricter than a typical permissive grant. Self-hosting a personal site under that arrangement is one thing; putting it behind a company domain is a decision that needs an answer in writing.

Editorial conclusion

fish-island-backend is worth running if you want the aggregator itself rather than the hosted site, because the crawler aggregation, the Redis caching layer and the MySQL schema are all in the repository, and because the nginx configuration in the project documentation shows exactly which traffic goes to the HTTP service on port 8123 and which goes to the WebSocket service on port 8090. It is the wrong tool for anything that needs a maintained upstream feed, since the data sources are scraped and change without notice. Before you deploy it, check the three things the project states about itself: that you must run the initialisation SQL in sql/create_table.sql and set the MySQL, Redis, Minio and email configuration before starting, since the service will not create its own schema; that the front end is a separate repository, fish-island-frontend, and the self-hosted back end address has to be changed in it, as the project documentation warns; and the attribution requirement, since the note says users of the open source project must credit the author and link to the project, and must obtain authorisation before removing the credit.

Frequently asked questions

How do I deploy fish-island-backend?

Run the initialisation SQL in sql/create_table.sql, then set the MySQL, Redis, Minio and email configuration, package with Maven, and deploy with Docker using the provided Dockerfile, which exposes port 8123. The project documentation also supplies an nginx configuration, with a location for /fish/ proxying to port 8123 and a location for /ws/ proxying to port 8090 for the WebSocket traffic.

Which data sources does fish-island-backend aggregate?

The project documentation lists Zhihu, Weibo, Hupu, Coder Navigation, CSDN, Juejin, Bilibili, Douyin, NetEase Cloud Music and Smzdm, with the entry marked as to be filled in. The NetEase Cloud Music list is called out as supporting playback on the site, and the aggregation is described as crawler based.

What are the usage terms for the fish-island-backend project?

The project documentation states that users of the open source project must show the author's name on the site along with a link to the project, that removing the attribution requires obtaining authorisation first, and that the project must not be used for illegal purposes. The repository licence is not classified, so the licence file and the author need to be consulted for the exact terms.

Official sources

  1. Issues
  2. lhccong/fish-island-backend on GitHub
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lhccong-fish-island-backend.svg)](https://hysenlabs.com/projects/lhccong-fish-island-backend)

Was this useful?