A high-performance map tile proxy server with GCJ-02 coordinate transformation and multi-layer caching support. This service provides properly coordinate-transformed map tiles from various sources with persistent S3 storage and in-memory LRU caching.
- Multi-Layer Caching: In-memory LRU cache + S3 persistent storage
- Coordinate Transformation: WGS84 to GCJ-02 (China Mars Coordinate System)
- Multiple Map Sources: Support for Amap, Google Maps, and other tile sources
- RESTful API: Clean and intuitive REST API endpoints
- Docker Support: Ready-to-use Docker and Docker Compose configurations
- Health Monitoring: Built-in health checks and cache statistics
- Environment Configuration: Flexible configuration via environment variables
- TypeScript: Full TypeScript support with type safety
- Node.js (v18 or higher)
- pnpm (package manager)
- AWS S3 or MinIO (for persistent storage - optional)
# Clone repository
git clone <repository-url>
cd maptile
# Install dependencies
pnpm install
# Copy environment configuration
cp .env.example .env
# Edit configuration as needed
vim .env
# Start development server
pnpm dev# Build the project
pnpm build
# Start production server
pnpm start# Build image
docker build -t maptile-server .
# Run with basic configuration
docker run -p 5000:5000 \
-e MAP_SOURCE="https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=YOUR_KEY" \
-e PORT=5000 \
-e CACHE_MAX_SIZE=200 \
-e CACHE_RESET_INTERVAL=60000 \
-e TILE_LOAD_TIMEOUT=30000 \
maptile-server
# Run with AWS S3 storage
docker run -p 5000:5000 \
-e MAP_SOURCE="https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=YOUR_KEY" \
-e PORT=5000 \
-e CACHE_MAX_SIZE=500 \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID=your-access-key \
-e AWS_SECRET_ACCESS_KEY=your-secret-key \
-e S3_BUCKET=your-bucket-name \
-e S3_PREFIX=tiles \
maptile-server
# Run with MinIO/S3-compatible storage
docker run -p 5000:5000 \
-e MAP_SOURCE="https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=YOUR_KEY" \
-e PORT=5000 \
-e CACHE_MAX_SIZE=200 \
-e S3_ENDPOINT=http://your-minio-server:9000 \
-e S3_BUCKET=map-tiles \
-e AWS_ACCESS_KEY_ID=minioadmin \
-e AWS_SECRET_ACCESS_KEY=minioadmin \
-e S3_PREFIX=tiles \
maptile-server
# Run with environment file
docker run -p 5000:5000 --env-file .env maptile-serverCopy .env.example to .env and configure as needed:
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 5000 |
MAP_SOURCE |
Map tile source URL template | Amap URL |
CACHE_MAX_SIZE |
Maximum in-memory cache size | 200 |
CACHE_RESET_INTERVAL |
Cache reset interval (ms) | 60000 |
TILE_LOAD_TIMEOUT |
Tile loading timeout (ms) | 30000 |
LOG_LEVEL |
Logging level | info |
| Variable | Description | Required |
|---|---|---|
S3_BUCKET |
S3 bucket name for tile storage | β |
AWS_REGION |
AWS region | β |
AWS_ACCESS_KEY_ID |
AWS access key (optional with IAM) | β |
AWS_SECRET_ACCESS_KEY |
AWS secret key (optional with IAM) | β |
S3_ENDPOINT |
S3 endpoint (for MinIO/S3-compatible) | β |
S3_PREFIX |
S3 key prefix for tiles | tiles |
# AWS S3
S3_BUCKET=map-tiles-prod
AWS_REGION=us-west-2
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...# MinIO
S3_ENDPOINT=http://localhost:9000
S3_BUCKET=map-tiles
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin# Skip S3 - only use in-memory cache
# S3 storage is automatically disabled when neither S3_ENDPOINT nor AWS credentials are providedNote: S3 storage is only enabled when at least one of the following is configured:
S3_ENDPOINT(for MinIO or S3-compatible services)- Both
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY(for AWS S3)
When S3 is disabled, the service will only use in-memory LRU caching.
GET /appmaptile?x={x}&y={y}&z={z}Parameters:
x(int): Tile x coordinatey(int): Tile y coordinatez(int): Zoom level
Response:
200 OK: PNG image400 Bad Request: Invalid parameters500 Internal Server Error: Server error
Example:
curl "http://localhost:5000/appmaptile?x=100&y=200&z=10"GET /healthResponse:
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00.000Z",
"cacheStats": {
"size": 150,
"maxSize": 200,
"usage": "75%"
}
}GET /cache-statsResponse (with S3 enabled):
{
"lruCache": {
"size": 150,
"maxSize": 200,
"usage": "75%"
},
"s3Enabled": true,
"s3Bucket": "map-tiles",
"s3Prefix": "tiles",
"s3Region": "us-east-1"
}Response (with S3 disabled):
{
"lruCache": {
"size": 150,
"maxSize": 200,
"usage": "75%"
},
"s3Enabled": false
}POST /reset-cacheResponse:
{
"status": "success",
"message": "Cache reset successfully",
"cacheStats": {
"size": 0,
"maxSize": 200,
"usage": "0%"
}
}Note: S3 cache endpoints are only available when S3 storage is enabled.
GET /s3-cache/check?z={z}&x={x}&y={y}Response (S3 enabled):
{
"exists": true,
"tile": "100-200-10",
"url": "s3://map-tiles/tiles/10/100/200.png"
}Response (S3 disabled):
{
"error": "S3 storage is not enabled"
}POST /s3-cache/clear?z={z}&x={x}&y={y}Response (S3 enabled):
{
"status": "success",
"message": "S3 cache cleared for tile 100-200-10"
}Response (S3 disabled):
{
"error": "S3 storage is not enabled"
}- Memory Cache (LRU): Fast access for recently used tiles
- S3 Storage: Persistent cache across service restarts
- Source: Original tile provider
Client Request β Memory Cache β S3 Cache β Source β Save to Caches β Response
- Memory: 200 tiles max (configurable)
- S3: Unlimited persistent storage
- Async Storage: S3 writes are non-blocking
- TTL: 1-year cache headers for S3
- Usage: Required for Chinese map services
- Transformation: WGS84 β GCJ-02
- Accuracy: Precise coordinate conversion
- Boundary: Smart handling outside China
- EPSG:4326 (WGS84)
- EPSG:3857 (Web Mercator)
- GCJ-02 (China Mars)
# Development
pnpm dev
# Build
pnpm build
# Start production
pnpm start
# Linting
pnpm lint
# Testing
pnpm testmaptile/
βββ src/
β βββ index.ts # Main server
β βββ storage.ts # S3 storage implementation
β βββ gcj02.ts # GCJ-02 coordinate transformation
βββ dist/ # Build output
βββ nginx/ # Nginx configuration
βββ Dockerfile # Docker configuration
βββ docker-compose.yaml # Docker Compose setup
βββ .env.example # Environment template
# Check S3 credentials
aws s3 ls s3://your-bucket-name
# Test MinIO connection
curl http://localhost:9000/minio/health/live- Reduce
CACHE_MAX_SIZEfor low-memory environments - Monitor cache statistics at
/cache-stats
- Verify source URL format
- Check coordinate transformation accuracy
# Enable debug logging
LOG_LEVEL=debug pnpm dev- Response time tracking
- Cache hit/miss ratios
- S3 storage usage
- Error rates
- Structured JSON logs with pino
- Request/response timing
- Error stack traces
- Cache performance metrics
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
ISC License - see LICENSE file for details.
- OpenLayers for coordinate transformation
- Hono.js for the web framework
- AWS SDK for S3 integration
- GCJ-02 transformation algorithm implementation
For issues and questions:
- Check the troubleshooting section
- Review existing GitHub issues
- Create a new issue with detailed information