1. Problem
I’m currently running Nginx on my Ubuntu server to host my Rails application. However, my app uses Kamal, which requires Traefik, and both Nginx and Traefik utilize ports 80 and 443. To simplify my setup, I’d like to migrate Nginx to a Docker container while preserving my existing configurations. How do I make Traefik in front of Nginx?
I plan to:
- Uninstall Nginx from Ubuntu without disrupting my setup.
- Seamlessly migrate my existing Nginx configuration to work with the Nginx Docker container.
- Backup all critical files, including my Nginx configurations, to avoid any data loss.
- Continue using my current PHP 7.4 socket (without switching to a PHP Docker image), maintaining compatibility without requiring manual configuration changes.
- Set up Traefik in front of Nginx so that Traefik handles ports 80 and 443, with Nginx operating smoothly behind it.
My goal is to ensure a smooth, efficient transition with minimal downtime, so everything works as expected without unnecessary effort.
2. Solving
2.1/ Stop nginx service
sudo service nginx stop;
sudo systemctl disable nginx; # prevent nginx start when reboot
2.2/ Backup config
# Create a backup directory
mkdir -p ~/nginx-backup
# Backup the Nginx configuration files
sudo cp /etc/nginx/nginx.conf ~/nginx-backup/
sudo cp -r /etc/nginx/sites-available ~/nginx-backup/
sudo cp -r /etc/nginx/snippets ~/nginx-backup/
2.3/ Uninstall Nginx (optional)
sudo systemctl stop nginx
sudo apt remove nginx nginx-common
sudo apt purge nginx
2.4/ Traefik deployed by kamal
Because I’m using Rails to deploy traefik by Kamal, here’s the deploy.yml
, we can easily convert this file to docker-compose.yml
service: demo
# Name of the container image.
image: kokorolee/demo
servers:
web:
hosts:
- meeaws_deployer
labels:
traefik.enable: true
traefik.http.routers.demo.rule: Host(`shareopus.thnkandgrow.com`)
traefik.http.routers.demo.entrypoints: websecure
traefik.http.routers.demo.tls.certresolver: myresolver
options:
network: "traefik_network"
accessories:
db:
image: postgres:16.0
host: meeaws_deployer
env:
clear:
POSTGRES_USER: "demo"
POSTGRES_DB: 'demo'
secret:
- POSTGRES_PASSWORD
- POSTGRES_USER
files:
- config/deploy/init.sql:/docker-entrypoint-initdb.d/setup.sql
directories:
- data:/var/lib/postgresql/data
options:
network: "traefik_network"
# Credentials for your image host.
registry:
username: kokorolee
# Always use an access token rather than real password when possible.
password:
- KAMAL_REGISTRY_PASSWORD
# Inject ENV variables into containers (secrets come from .env).
# Remember to run `kamal env push` after making changes!
env:
secret:
- RAILS_MASTER_KEY
- POSTGRES_PASSWORD
- DB_HOST
- POSTGRES_USER
- PORT
# Use a different ssh user than root
ssh:
user: deployer
# Configure custom arguments for Traefik. Be sure to reboot traefik when you modify it.
traefik:
image: traefik:v3.1
options:
volume:
- "./.docker-data/traefik/letsencrypt:/letsencrypt"
publish:
- "443:443"
- "8080:8080"
network: "traefik_network"
args:
# api.insecure: true
providers.docker: true
providers.docker.exposedbydefault: false
entrypoints.web.address: ':80'
entryPoints.websecure.address: ':443'
certificatesresolvers.myresolver.acme.tlschallenge: true
certificatesresolvers.myresolver.acme.httpchallenge: true
certificatesresolvers.myresolver.acme.httpchallenge.entrypoint: 'web'
certificatesresolvers.myresolver.acme.email: '[email protected]'
certificatesresolvers.myresolver.acme.storage: '/letsencrypt/acme.json'
# Configure a custom healthcheck (default is /up on port 3000)
healthcheck:
path: /up
port: 5000
This configuration allows Traefik to automatically manage SSL certificates, route traffic.
2.5/ Adding a Docker Compose File for Nginx
# docker-compose.yml
version: "3.3"
services:
nginx:
image: nginx:latest
container_name: nginx
restart: unless-stopped
volumes:
- /home/deployer/.docker-data/nginx/nginx.conf:/etc/nginx/nginx.conf # Nginx main config
- /home/deployer/.docker-data/nginx/sites-available:/etc/nginx/sites-available # Site configs for multiple domains
- /home/deployer/.docker-data/nginx/sites-enabled:/etc/nginx/sites-enabled # Symlinks for enabled sites
- /home/deployer/.docker-data/nginx/snippets:/etc/nginx/snippets # PHP configs and snippets
- /home/deployer/.docker-data/nginx/fastcgi.conf:/etc/nginx/fastcgi.conf
- /var/www:/var/www # Your web files
- /var/run/php/php7.4-fpm.sock:/var/run/php/php7.4-fpm.sock # PHP socket on the host
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`example.space`) || HostRegexp(`^.+.example.space$`) || HostRegexp(`^.+.thnkandgrow.com$`)"
- "traefik.http.routers.nginx.entrypoints=websecure"
- "traefik.http.routers.nginx.tls.certresolver=myresolver"
- "traefik.http.services.nginx.loadbalancer.server.port=80"
- "traefik.http.routers.nginx.priority=1"
networks:
- traefik_network
networks:
traefik_network:
external: true
This docker-compose.yml
config allows Nginx to serve multiple hosts with SSL via Traefik, using domains like example.space
and thnkandgrow.com
, and all subdomains. It maps essential volumes for Nginx configurations (backed-up files) and PHP 7.4 socket.
The critical part is that both Nginx and Traefik must be on the same network (traefik_network
) to enable proper routing and SSL handling.
The label traefik.http.routers.nginx.priority=1
sets the priority for the Nginx router in Traefik.
- Purpose: It determines which router Traefik will use when multiple routers match a request.
- Lower Priority: A lower number (like
1
) means this router has a lower priority, so if other routers have a higher priority, they will handle the request first. - Use Case: This can be useful when you have multiple services or routers handling the same domain or subdomains, and you want to control which one takes precedence.
2.5/ Update some config to adapt new system
Updating Cloudflare SSL Settings to full
, not Full (strict)
# sites-enable/blog.thnkandgrow.com
server {
# ... current config
location / {
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;
# ...other config
}
# /var/www/blog.thnkandgrow.com/wp-config.php
# add this line
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') $_SERVER['HTTPS']='on'
Transitioning from an installed version of Nginx on Ubuntu to running it in a Docker container behind Traefik was a smooth and effortless process. By carefully backing up my configurations, leveraging Traefik for SSL, and updating my Docker and Nginx setups, I was able to ensure minimal downtime and a seamless transition.
If you’re considering a similar move, these steps should help make your migration painless. Happy deploying!
Thank you!
https://gist.github.com/kokorolx/2c2c72284b6945df47deedee8d2de950