I am completely new to docker, php and apache, I am trying to run my sample website on apache server in a docker container. It works fine. And my dockerfile is following:
From php:7.2-apache
Copy Site/ /var/www/html/
Run echo "ServerName localhost" >> /etc/apache2/apache2.conf
RUN docker-php-ext-install pdo pdo_mysql
Expose 80
How can I have another website on the same apache sever in the docker container, for example "website1", in xampp I could change the httpd.conf file and add virtual host. but what should I do in docker container?
Update
============================================
I update the files as the following, This is docker-compose.yml
version: '3.9'
services:
apache:
build: .
container_name: php_cont
volumes:
- './apache2.conf:/etc/apache2/apache2.conf'
- './Site1/site1.conf:/etc/apache2/sites-available/site1.conf'
- './Site2/site2.conf:/etc/apache2/sites-available/site2.conf'
ports:
- '80:80'
This is the site.conf
<VirtualHost *:80>
DocumentRoot "d:\Temp\Site1"
ServerName site1Name
<Directory "d:\Temp\Site1">
</Directory>
</VirtualHost>
This is the site2.conf
<VirtualHost *:80>
DocumentRoot "d:\Temp\Site2"
ServerName site2Name
<Directory "d:\Temp\Site2">
</Directory>
</VirtualHost>
and I addded these two line to hosts file in windows=>system32=>driver=>etc
127.0.0.1 site1Name
127.0.0.1 site2Name
but when I surf to site1Name or site2Name on the browser, there is no success!
The idea of Docker is that every application (website in you case) has its own environment. You can then upgrade the PHP version for one application without affecting the others. So you should have a Dockerfile per website.
To answer your question “how to direct visitors to the correct container?”: please take a look into Reverse Proxies. There are plenty of Docker images available like Nginx and Traefik. These can also take care of SSL certificates for instance.
I recommend you using Docker Compose, but you also can use Volume in both docker run command and docker-compose.
docker-compose
First of all let's see docker-compose. Create a file called docker-compose.yml with the following contents:
version: '3.9'
services:
apache:
build: .
hostname: OPTIONAL
container_name: OPTIONAL
volumes:
- './apache/apache2.conf:/etc/apache2/apache2.conf'
- './apache/site1.conf:/etc/apache2/sites-available/site1.conf'
ports:
- '80:80'
The two keywords hostname and container_name are optional and you can change their values or even remove these two lines.
Regarding volumes, copy your apache2.conf to a path like ./apache and do your edits in this file.
Then add another file called site1.conf. Here is my conf file as an example:
<VirtualHost *:80>
ServerName some_name.com
ServerAdmin webmaster#name
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
For each site you can create another file and add it to volumes.
Now after everything is done, run this command:
docker-compose up -d
docker run command
If you want to use docker run command, you can do like this (the above paths in ./apache in the below are the same):
docker run IMAGE_NAME -v './apache/apache2.conf:/etc/apache2/apache2.conf' -v './apache/site1.conf:/etc/apache2/sites-available/site1.conf' -dp80:80
Update 1
Edit your Dockerfile:
From php:7.2-apache
Copy Site/ /var/www/html/
Run echo "ServerName localhost" >> /etc/apache2/apache2.conf
COPY site1.conf /etc/apache2/apache2.conf
COPY site2.conf /etc/apache2/apache2.conf
COPY apache2.sh /root/
RUN bash /root/apache2.sh
RUN rm /root/apache2.sh
RUN docker-php-ext-install pdo pdo_mysql
Expose 80
apache2.sh:
service apache2 start
a2ensite site1
a2ensite site2
service apache2 restart
Related
I've followed suit to quite some instructions, tutorials, and also questions in this forum, but I can still not get this working. I've setup a REST API using a PHP Apache Docker container, and need to create a rewrite rule in my apache config to reroute API requests to index.php (the REST controller). Currently, with what's written below, I'm getting a 404:
File Structure on local machine (listed everything except php source code; not needed here):
php
conf.d
- error_reporting.ini
- xdebug.ini
Dockerfile
index.php
apache
- apache2.conf
docker-compose.yml
The content of the Dockerfile being:
FROM php:8.1-apache
WORKDIR /var/www/html/
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug \
&& a2enmod rewrite
COPY . .
EXPOSE 80
And the content of docker-compose.yml being:
services:
php:
build: ./php
depends_on:
- db
container_name: php-apache
ports:
- 80:80
volumes:
- ./php:/var/www/html
- ./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
- ./php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
- ./apache/apache2.conf:/etc/apache2/apache2.conf
environment:
MARIADB_HOST: localhost
MARIADB_USER: root
MARIADB_PASSWORD: top_very_secret
MARIADB_DB: apidb
adminer:
image: adminer
depends_on:
- db
restart: always
ports:
- 8080:8080
db:
image: mariadb
container_name: db
volumes:
- maria-db-storage:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: top_very_secret
MARIADB_DATABASE: apidb
volumes:
maria-db-storage:
Regarding the contents of apache2.conf; I've done the following to create it on the local machine:
Went into the container's virtual filesystem using docker exec -t -i <container_name> /bin/bash.
Wandered to /etc/apache2
Printed the file contents via cat apache2.conf
Copy-pasted the contents into my local /apache/apache2.conf file
Added the following directive lines to the end of that local file:
# Custom directives start here
# Set Server's name
ServerName 'localhost'
# Rewrite for routing of all requests through REST controller
RewriteEngine On
# If requested resource is index.php, do nothing
RewriteRule ^index\.php$ - [L]
# If requested resource is a file or directory that does not exist, reroute to REST
# controller index.php
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule . /index.php [L]
After building the images and running the containers, I've checked within the container's virtual filesystem again via CLI. The /etc/apache2/apache2.conf successfully holds the contents of my local file, and I've also done a apachectl -M within the container, and can see rewrite_module (shared) getting printed.
Again, I'm simply getting a 404; for example if I search for http://localhost/xyz. Same if I do not omit the port (and search for http://localhost:80/xyz). Searching for http://localhost and http://localhost:80 both work; so it seems that my rewrite rules are simply not being applied.
When running apachectl configtest within the docker container, I also get Syntax OK.
Just guessing; does this maybe have something with xdebugs outgoing communication from the container's port 9003?
What am I missing?
Apparently serverfault is the intended place for these questions; so I posted it over there (don't know how to migrate): https://serverfault.com/questions/1115336/cant-get-apache-rewrite-to-work-on-docker-php-apache-container
I've actually figured it out. The problem seems to be that, when using docker, you must specify the rewrite rules within the Virtual Host context of the port you've specified. At least I've done what's written above, plus the following steps:
Within the container, I've migrated (in CLI) to the folder etc/apache2/sites-enabled
In there is the file 000-default.conf, holding the default configs for the sites that are currently enabled on the concerned apache unit. As far as this application is concerned, it's thus fine to modify the default configuration, as the container will exclusively be used for this API. At least that was my thought.
So again I did the same; copy the file contents as they're shipped with an initiated docker container, via cat 000-default.conf.
Copy-paste the contents within the local apache/sites-enabled/000-default.conf file (that you newly create)
Now you take the following part that was previously in the local apache2.conf file (slightly improved):
# Rewrite for routing of all requests through REST controller
RewriteEngine On
RewriteRule ^index\.php$ - [L]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^(.*)$ /index.php [L]
and paste it into the local 000-default.conf file; before the closing </VirtualHost> tag. Then you remove the rewrite rules from your apache/apache2.conf file, but you leave it for the added ServerName directive.
You then add the path mapping to the volumes of your php container to load your custom virtual host default configuration file into your container, and you should be good to go; so your docker-compose.yml becomes:
services:
php:
....
volumes:
- ./php:/var/www/html
- ./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
- ./php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
- ./apache/apache2.conf:/etc/apache2/apache2.conf
- ./apache/sites-enabled/000-default.conf:/etc/apache2/sites-enabled/000-default.conf
....
Rewrite is now fully functional!
I have to host 2 different web apps from a docker container. My first attempt at this worked, but I didn't like it. I have a lamp-base folder that has the Dockerfile that gets the server working, then a docker-compose.yml file that puts everything together. In my first version for the web apps I did build: ./lamp-base/ to make them build the web server, but I feel like that's the wrong approach as it leaves me with 3 images (one for each web app and one for the mysql server). I feel like this should be 2 images and 3 containers. 1 image for the mysql container and 1 image for the web server, then the web apps should be able to use the web server. I was able to build it and make it work, kind of.
The problem is, when I go to the URL I defined and added to my local /etc/hosts file I get the default welcome to apache page, I don't get my web apps. I honestly can't figure out why it isn't working correctly. The healthchecks pass, so the files are being hosted properly, but I can't access the web pages. This might be a little long, but I'll post up the Dockerfile and the docker-compose.yml file as well as the default.conf that get's added to the web server. I have asked all the people I know and no one can figure out why I can't reach the webpages, especially since the healthchecks pass. Thank you for bearing with me on this, here are the files...
Dockerfile...
FROM centos:7
EXPOSE 80/tcp
RUN yum install epel-release yum-utils -y && yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm -y
RUN yum-config-manager --enable remi-php74 && yum install php php-common php-opcache php-mcrypt php-cli php-gd php-curl php-mysql php-pdo php-pdo_mysql php-pecl-mcrypt php-sodium php-mbstring php-runtime php-json php-devel php-xml php-soap php-mysqlnd php-intl php-pecl-xlswriter httpd mod_ssl mod_php -y && yum clean all -y && rm /etc/httpd/conf.d/ssl.conf
ADD httpd.conf /etc/httpd/conf/httpd.conf
ADD conf.d/default.conf /etc/httpd/conf.d/default.conf
CMD /sbin/httpd -D FOREGROUND
The default.conf file that has the vhosts for the web apps...
<VirtualHost my.server1.com:80>
ServerName my.server1.com
CustomLog /var/log/httpd/access_log combinedio
ErrorLog /var/log/httpd/error_log
LogLevel notice
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F,L]
# Set application web root and directory settings
DocumentRoot "/var/www/server1/html"
<Directory "/var/www/server1/html">
Options -Indexes
AllowOverride none
php_value include_path ".:/var/www/server1/class"
php_value arg_separator.output ";"
php_value arg_separator.input ";"
</Directory>
</VirtualHost>
<VirtualHost my.server2.com:80>
ServerName my.server2.com
CustomLog /var/log/httpd/access_log combinedio
ErrorLog /var/log/httpd/error_log
LogLevel notice
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK)
RewriteRule .* - [F,L]
# Set application web root and directory settings
DocumentRoot "/var/www/server2/html"
<Directory "/var/www/server2/html">
Options -Indexes
AllowOverride none
php_value include_path ".:/var/www/server2/class"
php_value arg_separator.output ";"
php_value arg_separator.input ";"
</Directory>
</VirtualHost>
I renamed the servers because I don't think I can post the actual server names, sorry.
The docker-compose.yml file...
version: "3.7"
networks:
lamp-net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
services:
lamp-web:
build: ./lamp-base/
image: lamp-web:dev
networks:
lamp-net:
ipv4_address: 172.20.0.6
ports:
- "80:80"
lamp-mysql:
image: mariadb:10.4
container_name: lamp-mysql
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
volumes:
- ./sql-files:/docker-entrypoint-initdb.d
networks:
lamp-net:
ipv4_address: 172.20.0.2
ports:
- "3307:3306"
healthcheck:
test: "/usr/bin/mysql --user=root --password=password --execute \"SHOW DATABASES;\""
interval: 3s
timeout: 2s
retries: 10
server-one:
image: lamp-web:dev
container_name: server-one
hostname: my.server1.com
depends_on:
lamp-mysql:
condition: service_healthy
volumes:
- ./server1:/var/www/server1
- ./Server1Config.php:/var/www/server1/class/Config.php
networks:
lamp-net:
ipv4_address: 172.20.0.3
healthcheck:
test: curl -kf http://server-one/home/landing/ || exit 1
interval: 3s
timeout: 2s
retries: 10
server-two:
image: lamp-web:dev
container_name: server-two
hostname: my.server2.com
volumes:
- ./server2:/var/www/server2
- ./Server2Config.php:/var/www/server2/class/Config.php
depends_on:
lamp-mysql:
condition: service_healthy
cr-web:
condition: service_healthy
networks:
lamp-net:
ipv4_address: 172.20.0.4
healthcheck:
test: curl -kf http://server-one/api/mp/inventory || exit 1
interval: 3s
timeout: 3s
retries: 10
It all builds correctly, I end up with 2 Images (mysql and server) and 3 containers (mysql, server-one, and server-two) all the healthchecks pass properly, but if I go to http://my.server1.com in my browser I only get the default apache welcome page, I don't get my actual server.
I have also tried removing the server from the docker-compose file and just doing docker build --no-cache . -t lamp-web:dev in the /lamp-base directory, then running the docker-compose up -d and again, it all builds properly I get the right containers, the healthchecks pass, but going to the URL in any browser just yields the default welcome to apache page. I can't figure out why the web containers aren't working correctly.
On a side note, if I remove the web server entirely and change the image: lamp-web:dev to build: ./lamp-base/ on both web containers it works correctly, but I end up with a bunch of images. Am I just going about this the wrong way? Should both the web containers have to build their own web server image? Any help is greatly appreciated. Thank you and sorry for the long post.
I'm currently configuring my raspberry pi as my personal home server and I want to use docker. I have few different containers :
-Apache/PHP 81:80
-Nextcloud 8080:80
-Minecraft 25565:25565
I already have a dynamic domaim (http://felixbestwaifu.hopto.org)
When I try to access felixbestwaifu.hopto.org:8080, it timeouts :c
My goal
Nextcloud
cloud.hostname.org
or hostname.org/nextcloud
Website
Domain.org
Domain.org/about.php
Domain.org/Anime.php
I tried using NGINX by creating a nextcloud.conf in /sites-enabled/ and /sites-available/, but it didn't work at all ^^'
server {
listen 80;
server_name nextcloud;
location /nextcloud {
proxy_pass 192.168.2.150:8080/;
}
}
Note : 192.168.2.150 is my pi static IP in my network
So here is my question : How do you set-up a reverse proxy for docker containers ?
I would really appreciate your help >//< (sorry for bad English)
Let us suppose your Apache-PHP container is called apache_php. You should have two .conf files there with similar contents (less or more is regarding what you need in your conf files).
/etc/apache2/sites-available/minecraft.conf:
<VirtualHost *:80>
ServerName minecraft.com
ServerAdmin webmaster#minecraft
DocumentRoot /home/minecraft
ProxyPreserveHost On
ProxyPass "/" "http://minecraft:25565/"
ProxyPassReverse "/" "http://minecraft:25565/"
ProxyRequests Off
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
/etc/apache2/sites-available/nextcloud.conf:
<VirtualHost *:80>
ServerName nextcloud.com
ServerAdmin webmaster#nextcloud
DocumentRoot /home/nextcloud
ProxyPreserveHost On
ProxyPass "/" "http://nextcloud:8080/"
ProxyPassReverse "/" "http://nextcloud:8080/"
ProxyRequests Off
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Note the trailing / in ProxyPass and ProxyPassReverse. If you do not add them, final URLs will be something like http://minecraft:25565your_page, while with trailing / it will be http://minecraft:25565/your_page.
In this case if anyone enters minecraft.com, your Apache proxies him to minecraft site and *minecraft is only accessible by your Apache container.
Note that minecraft.com and minecraft are two different websites in a network called proxy that I talk about it below
This is what I do in my container, but let me explain it up to my knowledge:
Suppose Your Apache, your Nextcloud and Minecraft are in the same network (in this case you should create a network, in my case it's called proxy network) and all of these three containers should see each other by pinging.
How your docker-compose.yml file should look like in this case:
version: '3.9'
services:
apache_php:
build: .
restart: always
ports:
- "81:80"
minecraft:
build: .
restart: always
ports:
- "25565:25565"
nextcloud:
build: .
restart: always
ports:
- "8080:80"
networks:
default:
external:
name: proxy
volumes:
db_data: {}
So in this file, I'm creating three images called apache_php, minecraft and nextcloud that is built via Dockerfile via build keyword. I also proxy ports 81 to 80, port 25565 to 25565 and port 8080 to 80.
Then you can create a Dockerfile or modify existing one with similar contents:
FROM your_os_base:tag
COPY minecraft.conf /etc/apache2/sites-available/
COPY nextcloud.conf /etc/apache2/sites-available/
COPY my_bash_commands.sh /root/
RUN chmod +x /root/my_bash_commands.sh
RUN /root/my_bash_commands.sh
ENTRYPOINT ["your_thing"]
Now what is my_bash_commands.sh in my case? As default shell is sh in most cases, I create a bash file so that I get my desired results.
The my_bash_commands.sh is similar to this:
#!/usr/bash
service apache2 start
a2ensite minecraft
a2ensite nextcloud
a2enmod proxy
a2enmod proxy_http
service apache2 restart
Now you can create them by running docker-compose up -d if you are in the path where docker-compose.yml is, else you should use docker-compose -f /absolute_patht_to/docker-compose.yml up -d.
Summary: 2 separate applications, both using docker-compose, how can I have http://app-1.test and http://app-2.test available at the same time?
Description:
I feel like I've missed something super-simple. I have 2 php-fpm (via nginx) applications, both run by similar docker-compose setups, somewhat like:
# docker-compose.yaml
version: '3'
services:
app:
build:
context: .
dockerfile: docker/Dockerfile
container_name: app_1
tty: true
depends_on:
- db
- dbtest
working_dir: /var/www
volumes:
- ./:/var/www
webserver:
image: nginx:stable
container_name: app_1_webserver
restart: always
ports:
- "80:80"
depends_on:
- app
volumes:
- ./:/var/www
- ./docker/app.conf:/etc/nginx/conf.d/default.conf
links:
- app
# ...
On my /etc/hosts, I can add something like
127.0.0.1 app-1.test
Now I can call the app via the browser by going to app-1.test.
The second one has a similar setup, but of course it won't go up, because port 80 is blocked. I can of course change the port, but then the url would be something like app-2.test:81 instead of app-2.test. What can I do, so I can run a second application under a different local hostname? Or is using a different port the best way to go?
You can't. What you can do is add a "router" in front of your images (a third image) which does routing (proxy passing) based on the host name.
Apache or Nginx are often used for these kinds of things.
e.g. with apache server
https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html
<VirtualHost *:80>
ServerName app-1.test
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://image1:80/
ProxyPassReverse / http://image1:80/
ErrorLog /var/log/apache2/error.log
LogLevel info
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
<VirtualHost *:80>
ServerName app-2.test
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://image2:80/
ProxyPassReverse / http://image2:80/
ErrorLog /var/log/apache2/error.log
LogLevel info
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
now you can add both names on the same ip in your /etc/hosts file and the server can route internally based on the provided hostname (ServerName).
The http://image1:80/ (and its like) references should be changed to the docker internal dns like specified in the docker-compose.yml
i'm trying to make a reverse proxy and dockerize it for my flask application with nginx, gunicorn, docker and docker-compose . Before that the nginx part was in the same container than the web app, i'm trying to separe it.
My docker_compose yaml file is :
version: '3.6'
services:
nginx:
restart: always
build: ./nginx/
ports:
- 8008:8008
networks:
- web_net
flask_min:
build: .
image: flask_min
container_name: flask_min
expose:
- "8008"
networks:
- web_net
depends_on:
- nginx
networks:
web_net:
driver: bridge
My dockerfile is :
FROM python:3.6
MAINTAINER aurelien beliard (email#domain.com)
RUN apt update
COPY . /usr/flask_min
WORKDIR /usr/flask_min
RUN useradd -r -u 20979 -ms /bin/bash aurelien.beliard
RUN pip3 install -r requirements.txt
CMD gunicorn -w 3 -b :8008 app:app
my nginx docker file is
FROM nginx
COPY ./flask_min /etc/nginx/sites-available/
RUN mkdir /etc/nginx/sites-enabled
RUN ln -s /etc/nginx/sites-available/flask_min /etc/nginx/sites-enabled/flask_min
my nginx config file in /etc/nginx sites-available and sites-enabled is named flask-min :
server {
listen 8008;
server_name http://192.168.16.241/ ;
charset utf-8;
location / {
proxy_pass http://flask_min:8008;
} }
the requirements.txt file is :
Flask==0.12.2
grequests==0.3.0
gunicorn==19.7.1
Jinja2==2.10
The 2 containers are well created, gunicorn start well but i can't access to the application and there is nothing in the nginx access and error log .
If you have any idea it will be very appreciated.
ps sorry for the fault english is not my native language.
As mentioned in Maxm's answer, flask is depending on nginx to startup first. One way to fix it is to reverse the dependency order, but I think there's a more clever solution that doesn't require the dependency.
Nginx tries to do some optimization by caching the dns results of proxy_pass, but you can make it more flexible by setting it to a variable. This allows you to freely restart flask without having to also restart nginx.
Here's an example:
resolver 127.0.0.11 ipv6=off;
set $upstream http://flask_min:8008;
proxy_pass $upstream;
server_name should just be the host. try localhost or just _.
you can also do multiple hosts: server_name 192.168.16.241 localhost;
The depends_on should be on nginx not flask_min. Remove it from flask and add:
depends_on:
- flask_min
To nginx.
See if that works, let me know if you run into any more snags.