A next-generation short URL SaaS solution built with PHP + PostgreSQL, tailored for startup teams, e-commerce platforms, and small to medium-sized enterprises. 🚀
Live Demo | Project Website | 中文文档
Demo Admin URL: https://zuz.asia/admin
Demo Admin Token: admintoken
The demo site clears data periodically—please don't use it for long-term needs. For production short URL services, visit the official site.
Releases are for version announcements only. For usage, please fork this repo or use one-click deployment.
Due to some conflicts between Vercel and PHP, features relying on Composer—like QR code generation and live code management—have beentemporarily suspended. 1
The current warehouse is updated with the 1.1.9-C2 stable version, and the Docker warehouse has been updated synchronously.
- Docker Deployment
- Apache + PostgreSQL Deployment
- Environment Variable Format
- Local Testing
- Database Migration
- About Free Vercel Deployment
- Free Database Option (Supabase)
⚠️ Contribution Policy Exception Notice
This project provides Docker image support, built with Apache + PHP 8.3, exposing port 8437 (customizable). The image includes the pdo_pgsql extension, enables rewrite and env modules, and is pre-configured for URL rewriting. Docker Compose is not supported yet—use docker run for manual deployment.
- Install Docker (official download).
- Prepare a PostgreSQL database (see Free Database Option (Supabase) or deploy manually).
- Environment variables:
DATABASE_URLandADMIN_TOKEN(format in Environment Variable Format).
docker pull janephpdev/zuzshorturl:latestdocker run -d \
--name zuzshorturl-app \
-e DATABASE_URL=postgresql://<your-username>:<your-password>@<database-host>:<port>/<database-name> \
-e ADMIN_TOKEN=<your-admin-token> \
-p 8437:8437 \
janephpdev/zuzshorturl:latest- Parameter Notes:
-d: Run in detached mode (background).--name: Container name (for easy management, e.g.,docker stop zuzshorturl-appto stop).-e: Inject environment variables (replace placeholders).-p 8437:8437: Port mapping (host 8437 → container 8437).
- Custom Port: For a different port, use
-p 8080:8437(host 8080 → container 8437).
- Open your browser and visit
http://localhost:8437(or your custom port). - On first run, perform database migration: Visit
http://localhost:8437/migrate, enterADMIN_TOKEN, and click "Run Migration". - After successful migration, you'll be redirected to the admin panel (
/admin).
Proxy port 8437 in your host's Nginx config (example for /etc/nginx/sites-available/default):
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:8437;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}- Restart Nginx:
sudo systemctl restart nginx. - Configure SSL for HTTPS (e.g., via Let's Encrypt).
- View logs:
docker logs zuzshorturl-app. - Stop/remove:
docker stop zuzshorturl-app && docker rm zuzshorturl-app. - Update image: Pull the new version and rerun.
Tip: If your PostgreSQL database is on the host machine, use the server's public IP for the database host, not 127.0.0.1—inside Docker, 127.0.0.1 refers to the container itself, not the host.
First, create the database and user, and grant necessary permissions (replace placeholders like <database-name> with actual values, e.g., zuz_db):
-- Create database
CREATE DATABASE <database-name>;
-- Create user
CREATE USER <database-username> WITH PASSWORD '<database-password>';
-- Grant database privileges
GRANT ALL PRIVILEGES ON DATABASE <database-name> TO <database-username>;
-- Connect to the database
\c <database-name>
-- Grant schema privileges (important!)
ALTER SCHEMA public OWNER TO <database-username>;
GRANT ALL ON SCHEMA public TO <database-username>;Tip: No need to reconnect after running these. 💡
Edit your Apache config file (usually in /etc/apache2/sites-available/ or /etc/httpd/conf.d/):
<VirtualHost *:80>
# Force redirect to HTTPS
Redirect permanent / https://<your-domain>/
</VirtualHost>
<VirtualHost *:443>
# Document root
DocumentRoot /var/www/<site-root>/api
# Environment variables (use English comments to avoid parsing issues)
SetEnv DATABASE_URL "postgresql://<your-username>:<your-password>@<database-host>:<port>/<database-name>"
SetEnv ADMIN_TOKEN "<your-admin-token>"
</VirtualHost>Tip: Set up SSL certificates for HTTPS (e.g., with Let's Encrypt) for security. 🔒
# Enable rewrite module (for URL rewriting)
sudo a2enmod rewrite
# Enable env module (for environment variables)
sudo a2enmod env
# Restart Apache
sudo systemctl restart apache2# Enter project directory
cd /var/www/<site-root>
# Set owner to Apache user (may be www-data or apache depending on your system)
sudo chown -R www-data:www-data .
# Set appropriate permissions (for production, refine: PHP files 644, dirs 755)
sudo chmod -R 755 .For database migration to work, ensure:
- PostgreSQL service is running
- PHP has the
pdo_pgsqlextension installed -
⚠️ If permissions are insufficient, check user settings
The project stores the PostgreSQL connection string and admin login token as environment variables for maximum security.
For deployment on a personal VPS, refer to the sections above. If not using Apache, manually add these to your environment variables.
DATABASE_URL=postgresql://<your-username>:<your-password>@<database-host>:<port>/<database-name>
ADMIN_TOKEN=your-tokenAfter entering the project root directory, use the following command for local debugging:
php -S localhost:8000 -t . api/index.phpWhen using servers like Nginx, Apache, or IIS, set the root directory to api/, and configure URL rewriting.
Apache rewriting rules are already built into the code.
After initial deployment or database reset, manually run the migration to set up the table structure. Your PostgreSQL user needs CREATE privileges. Follow these steps:
- Ensure
DATABASE_URLandADMIN_TOKENenvironment variables are set. - Visit
your-domain/migratein your browser. - Enter the admin token.
- Click the "Run Migration" button.
- On success, you'll be automatically redirected to the admin panel.
❗ Note: Run migration only once—re-running isn't needed. Without migration, the system may not function properly.
Common Migration Failure Causes:
- Insufficient privileges: Ensure the user has CREATE permissions.
- Incorrect token: Double-check the environment variable.
- Database connection failure: Verify DATABASE_URL format.
To accommodate users looking for free hosting, we've added specific support for Vercel.
Fork this repo, then import it into your Vercel dashboard and fill in the environment variables as per the format above.
Or use the one-click deploy link below—after deployment, add env vars and redeploy once.
After deployment, run the initial migration on first access—see the steps above:
- Ensure
DATABASE_URLandADMIN_TOKENenvironment variables are set.- Visit
your-domain/migratein your browser.- Enter the admin token.
- Click the "Run Migration" button.
- On success, you'll be automatically redirected to the admin panel.
| Step | Action |
|---|---|
| 1 | Sign up at Supabase → Create a new Project (free tier: 500 MB storage, 5M API calls/day) |
| 2 | In the breadcrumb nav, find the Connect button → Select URI format → Choose Session pooler |
| 3 | Copy the connection string, which looks like: postgresql://username:[email protected]:5432/postgres (mask password like *** for safety) |
| 4 | Paste the string into Vercel's DATABASE_URL env var—no need to create tables manually; the app auto-migrates on first access |
Supabase's free tier is plenty for personal use. Upgrade on-demand if you exceed limits. 💰
This project is open-source under the MIT License, allowing free use, modification, distribution, and commercial applications.
However, I explicitly reject all pull requests (PRs). Please do not submit PRs—they will be closed immediately.
If you have new ideas, open an Issue instead, and I'll consider them. For urgent bugs or security issues, email [email protected].
You're welcome to fork and maintain your own branch, but do not attempt to merge changes back into this repo.
⛔ This isn't standard open-source practice, but it's my choice.
Footnotes
-
Strikethrough here indicates a feature adjustment, but it's not fully removed—only limited by Vercel. ↩

