How to Self-Host LinkAce with Docker Compose
A Bookmark Manager That Watches Your Links
LinkAce doesn’t just store bookmarks — it monitors them. It periodically checks whether your saved URLs are still alive and flags dead links. Combined with tags, lists, and a REST API, it’s a capable self-hosted alternative to Raindrop.io and Pinboard. The stack is heavier than some alternatives (PHP/Laravel with MariaDB, Redis, and nginx), but the link monitoring feature justifies the overhead if dead link detection matters to you. linkace.org
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 512 MB of free RAM (4 containers: app, nginx, MariaDB, Redis)
- A domain name (recommended for remote access)
Docker Compose Configuration
LinkAce requires four services: the PHP application, an nginx web server, MariaDB, and Redis. Create a docker-compose.yml:
services:
db:
image: mariadb:11.2
container_name: linkace-db
restart: unless-stopped
command: mariadbd --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ${DB_DATABASE}
volumes:
- linkace-db:/var/lib/mysql
app:
image: linkace/linkace:v2.5.1
container_name: linkace-app
restart: unless-stopped
depends_on:
- db
volumes:
- ./.env:/app/.env
- ./backups:/app/storage/app/backups
- linkace-app:/app
- linkace-logs:/app/storage/logs
nginx:
image: bitnami/nginx:1.24
container_name: linkace-nginx
restart: unless-stopped
ports:
- "80:8080"
depends_on:
- app
volumes:
- linkace-app:/app
- ./nginx.conf:/opt/bitnami/nginx/conf/server_blocks/linkace.conf:ro
redis:
image: bitnami/redis:7.2
container_name: linkace-redis
restart: unless-stopped
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD}
volumes:
linkace-app:
linkace-logs:
linkace-db:
Create a .env file with your configuration:
# --- Application ---
APP_KEY=base64:GENERATE_THIS_KEY
APP_URL=http://localhost
APP_ENV=production
APP_DEBUG=false
APP_TIMEZONE=UTC
# --- Database ---
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=linkace
DB_USERNAME=linkace
DB_PASSWORD=change-this-strong-password
# --- Redis ---
REDIS_HOST=redis
REDIS_PASSWORD=change-this-redis-password
REDIS_PORT=6379
# --- Cache & Sessions (use Redis) ---
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_DRIVER=database
# --- Email (optional, for notifications) ---
MAIL_MAILER=log
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=null
MAIL_PASSWORD=null
# --- Link checking ---
META_GENERATION_TIMEOUT=10
# --- Reverse proxy ---
TRUSTED_PROXIES=*
Generate the APP_KEY:
docker run --rm linkace/linkace php artisan key:generate --show
Copy the base64:... output into your .env file.
Create the nginx.conf file in the same directory. Download it from the LinkAce release (included in linkace-docker.zip), or create it manually:
server {
listen 0.0.0.0:8080;
root /app/public;
index index.php;
client_max_body_size 20M;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Start everything:
docker compose up -d
Initial Setup
- Open
http://your-serverin your browser - The web-based setup wizard appears — it configures the database and creates your admin account
- Follow the prompts: confirm database settings, set your admin email and password
- After setup, you’re logged into the dashboard
LinkAce is ready to use. Start adding bookmarks via the web UI, browser extension, or API.
Configuration
| Setting | .env Variable | Default | Notes |
|---|---|---|---|
| Base URL | APP_URL | http://localhost | Change to your actual domain |
| Timezone | APP_TIMEZONE | UTC | PHP timezone string |
| Session lifetime | SESSION_LIFETIME | 10080 (7 days) | Minutes |
| Metadata timeout | META_GENERATION_TIMEOUT | 10 | Seconds to wait when fetching link titles/descriptions |
| Automated backups | BACKUP_ENABLED | false | Enable for scheduled database backups |
| Queue driver | QUEUE_DRIVER | database | Handles background jobs (link checking, metadata fetching) |
Link Monitoring
LinkAce’s standout feature is automatic dead link detection. The queue worker checks saved URLs periodically and flags broken links (404s, timeouts, DNS failures) in the dashboard. The check runs as a background job via the queue driver.
To ensure link checking works:
- Set
QUEUE_DRIVER=databasein.env - The built-in supervisor process handles queue workers automatically
- Dead links appear with a warning indicator in your bookmark list
Reverse Proxy
When running behind an external reverse proxy (Nginx Proxy Manager, Caddy, Traefik), proxy to linkace-nginx:8080. Set these headers in your proxy config:
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
Set APP_URL to your public HTTPS URL and TRUSTED_PROXIES=* in .env. See Reverse Proxy Setup.
Backup
LinkAce includes built-in backup support. Enable it in .env:
BACKUP_ENABLED=true
BACKUP_DISK=local_backups
Backups are stored in the ./backups bind mount. You can also back up the MariaDB database directly:
docker compose exec db mariadb-dump -u linkace -p linkace > linkace-backup.sql
See Backup Strategy.
Troubleshooting
”500 Server Error” after setup
Symptom: The app shows a generic 500 error after initial setup or during use.
Fix: Check APP_KEY is set correctly in .env. Run: docker compose exec app php artisan config:clear. Check logs: docker compose logs app and look in the linkace-logs volume.
Setup wizard won’t complete
Symptom: The database configuration step hangs or fails.
Fix: Verify DB_HOST=db matches the service name. Ensure MariaDB has started: docker compose logs db. The utf8mb4_bin collation is required — the command: in the compose file sets this.
”Class not found” or autoload errors
Symptom: PHP class errors appear in logs.
Fix: The linkace-app named volume may have stale files from a previous version. Remove the volume and recreate: docker compose down -v && docker compose up -d. This forces a fresh application deploy.
Link checking not working
Symptom: Bookmarked links never get checked for dead status.
Fix: Ensure QUEUE_DRIVER=database is set. The queue worker runs via supervisor inside the app container. Check: docker compose exec app php artisan queue:work --once to manually trigger a job.
Redis connection refused
Symptom: Errors about Redis connection failures in logs.
Fix: Verify REDIS_PASSWORD in .env matches what’s set for the Redis service. The bitnami Redis image requires REDIS_PASSWORD to be set in both the Redis container and the app’s .env.
Resource Requirements
| Resource | Value |
|---|---|
| RAM (total, all 4 containers) | 250–400 MB idle |
| CPU | Low — single core sufficient |
| Disk (application) | ~500 MB |
| Disk (data) | Grows slowly with bookmarks; minimal per-link storage |
| Containers | 4 (app, nginx, MariaDB, Redis) |
The 4-container architecture makes LinkAce heavier than simpler alternatives like Linkding or Shiori.
Verdict
LinkAce is worth the setup complexity if dead link detection matters to you. The automated link monitoring — periodically checking whether your saved URLs still resolve — is a feature most bookmark managers skip entirely. Tags, lists, a REST API, and browser extensions round out a capable tool.
But if you don’t need link monitoring, Linkding is the better choice for most people. It’s a single container, uses SQLite, and has a cleaner UI. Linkwarden offers more features (screenshots, collaboration) if you want something richer. LinkAce sits in between — more capable than Linkding, less polished than Linkwarden.
FAQ
Can I use PostgreSQL instead of MariaDB?
Yes. Set DB_CONNECTION=pgsql in .env and replace the MariaDB service with PostgreSQL. The official compose file includes a commented-out PostgreSQL service as a reference. Most users stick with MariaDB since that’s the primary tested configuration.
Does LinkAce have a browser extension?
Yes — extensions are available for Firefox and Chrome/Edge. They let you save the current page as a bookmark with one click. Install from your browser’s extension store and point it at your LinkAce instance URL.
How does LinkAce compare to Linkding?
Linkding is simpler (single container, SQLite), lighter, and faster to set up. LinkAce has link monitoring, more organizational features (lists in addition to tags), and a REST API. Choose Linkding for simplicity; choose LinkAce for link health monitoring. See LinkAce vs Linkding.
Related
Get self-hosting tips in your inbox
New guides, comparisons, and setup tutorials — delivered weekly. No spam.
Comments